大家好,我一直在尝试对我的CPU绑定函数进行异步处理,计算一些聚合函数。问题是存在一些死锁(我想),因为计算时间太不同了。我是这个任务并行世界的新手,我也读过Stephem Cleary的文章,但我仍然不确定这种异步方法的所有方面。 我的代码:
private static void Main(string[] args)
{
PIServer server = ConnectToDefaultPIServer();
AFTimeRange timeRange = new AFTimeRange("1/1/2012", "6/30/2012");
Program p = new Program();
for (int i = 0; i < 10; i++)
{
p.TestAsynchronousCall(server, timeRange);
//p.TestAsynchronousCall(server, timeRange).Wait();-same results
}
Console.WriteLine("Main check-disconnected done");
Console.ReadKey();
}
private async Task TestAsynchronousCall(PIServer server, AFTimeRange timeRange)
{
AsyncClass asyn;
for (int i = 0; i < 1; i++)
{
asyn = new AsyncClass();
await asyn.DoAsyncTask(server, timeRange);
//asyn.DoAsyncTask(server, timeRange);-same results
}
}
public async Task DoAsyncTask(PIServer server, AFTimeRange timeRange)
{
var timeRanges = DivideTheTimeRange(timeRange);
Task<Dictionary<PIPoint, AFValues>>[] tasksArray = new Task<Dictionary<PIPoint, AFValues>>[2];
tasksArray[0] = (Task.Run(() => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[0])));
// tasksArray[1] = tasksArray[0].ContinueWith((x) => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[1]));
tasksArray[1] = (Task.Run(() => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[1])));
Task.WaitAll(tasksArray);
//await Task.WhenAll(tasksArray); -same results
for (int i = 0; i < tasksArray.Length; i++)
{
Program.Show(tasksArray[i].Result);
}
}
我在AverageValueOfTagPerDay函数中通过秒表测量时间。这个功能是同步的(这是一个问题?)。每个任务需要12秒。但是当我取消注释该行并使用ContinueWith()方法时,这些任务每个需要5-6秒(这是可取的)。这怎么可能? 更奇怪的是,当我在10上的Main()中设置for循环时,有时需要5秒以及使用ContinueWith()时。所以我猜某个地方已陷入僵局,但我无法找到。 对不起英语,当我尝试解释一些困难时,我仍然有问题做好事。 干杯 更新我删除了过时的尝试,以便更清晰
答案 0 :(得分:3)
大家好,我一直在尝试对我的CPU绑定函数进行异步处理,计算一些聚合函数。
“Asynchronous”和“CPU-bound”不是一起使用的术语。如果你有一个CPU绑定的进程,那么你应该使用并行技术(Parallel
,Parallel LINQ,TPL Dataflow)。
我是这个任务并行世界的新手,我也读过Stephem Cleary文章,但我仍然不确定这种异步方法的所有方面。
可能是因为我没有在我的任何文章或博文中介绍并行技术。 :)我在书中覆盖了它们,但不在线。我的在线工作主要关注异步,这是基于I / O的操作的理想选择。
要解决您的问题,您应该使用并行方法:
public Dictionary<PIPoint, AFValues>[] DoTask(PIServer server, AFTimeRange timeRange)
{
var timeRanges = DivideTheTimeRange(timeRange);
var result = timeRanges.AsParallel().AsOrdered().
Select(range => CalculationClass.AverageValueOfTagPerDay(server, range)).
ToArray();
return result;
}
当然,这种方法假设PIServer
是线程安全的。它还假设“服务器”类没有进行I / O操作;如果有,那么TPL Dataflow可能是比Parallel LINQ更好的选择。
如果您打算在UI应用程序中使用此代码并且不想阻止UI线程,那么您可以异步调用代码,如下所示:
var results = await Task.Run(() => DoTask(server, timeRange));
foreach (var result in results)
Program.Show(result);