我有一个WCF服务,可以接受要约并“到达”并动态地向X数量的潜在买家(通常为15-20)提供此优惠,这些买家基本上是外部API。
每位买家目前有35秒的时间回复,或者他们失去了购买优惠的能力,
为了实现这一目标,我有以下代码已经生产了8个月,并且工作和扩展相当好。
由于我们最近花了很多时间进行改进以便我们可以进一步扩展,所以我一直对我是否有更好的选择来完成这项任务感兴趣。我在做出改变时犹豫不决,因为它现在工作得很好,但是当我能够专注于它时,我现在可以从中挤出额外的性能。
以下代码负责创建向买方发出出站请求的任务。
IBuyer[] buyer = BuyerService.GetBuyers(); /*Obtain potential buyers for the offer*/
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Tasks = new Task<IResponse>[Buyers.Count];
for(int i = 0; i < Buyers.Count;i++)
{
IBuyer buyer = Buyers[i];
Func<IResponse> makeOffer = () => buyer.MakeOffer()
Tasks[i] = Task.Factory.StartNew<IResponse>((o) =>
{
try
{
var result = MakeOffer();
if (!token.IsCancellationRequested)
{
return result;
}
}
catch (Exception exception
{
/*Do Work For Handling Exception In Here*/
}
return null;
}, token,TaskCreationOptions.LongRunning);
};
Task.WaitAll(Tasks, timeout, token); /*Give buyers fair amount of time to respond to offer*/
tokenSource.Cancel();
List<IResponse> results = new List<IResponse>(); /*List of Responses From Buyers*/
for (int i = 0; i < Tasks.Length; i++)
{
if (Tasks[i].IsCompleted) /*Needed so it doesnt block on Result*/
{
if (Tasks[i].Result != null)
{
results.Add(Tasks[i].Result);
}
Tasks[i].Dispose();
}
}
/*Continue Processing Buyers That Responded*/
平均而言,此服务的调用范围为每天400K-900K,有时甚至高达每秒30-40次。
我们在尝试调整性能方面做了很多优化,但我想确保这段代码没有任何直接的明显问题。
我读了很多关于TaskScheduler的强大功能并搞乱了SynchronizationContext和异步工作,我不知道如何才能做到这一点,是否值得改进。
答案 0 :(得分:2)
现在,您正在使用线程池线程(每个Task.Factory.StartNew
调用使用TP线程或完整的.NET线程,就像您的情况一样,由于LongRunning
提示)的工作实际上是IO绑定。如果您没有指定TaskCreationOptions.LongRunning
,那么您很早就会遇到问题,并且您将遇到线程池饥饿问题。你可能会使用非常多的线程,并且很快就会创建和销毁它们,这会浪费资源。
如果要使其完全异步,并使用新的async / await支持,则可以异步执行相同的“工作”,而不使用线程。这样可以更好地扩展,因为用于给定数量请求的线程数量将显着减少。
作为一般经验法则,Task.Factory.StartNew
(或.NET 4.5中的Task.Run
以及Parallel
类)仅应用于CPU绑定工作,{{{ 1}} / async
应该用于IO绑定工作,尤其是服务器端操作。