Ale*_*cka 0 c# asynchronous task task-parallel-library async-await
我一直在尝试对我的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
我在AverageValueOfTagPerDay 函数中通过秒表测量时间。这个函数是同步的(这是一个问题吗?)。每个任务需要 12 秒。但是当我取消注释该行并使用 ContinueWith() 方法时,这些任务每个需要 5-6 秒(这是可取的)。这怎么可能?
更奇怪的是,当我在 Main() 中将 for 循环设置为 10 时,有时需要 5 秒以及使用 ContinueWith() 时。所以我想某处是僵局,但我无法找到。
对不起英语,当我尝试解释一些困难时,我仍然遇到问题。
我一直在尝试对我的 CPU 绑定函数使用异步方法来计算一些聚合函数。
“异步”和“受 CPU 限制”不是一起使用的术语。如果您有一个受 CPU 限制的进程,那么您应该使用并行技术(Parallel并行 LINQ、TPL 数据流)。
我是这个任务并行世界的新手,我也阅读了 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;
}
Run Code Online (Sandbox Code Playgroud)
当然,这种方法假定它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);
Run Code Online (Sandbox Code Playgroud)