异步任务花费太多时间

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() 时。所以我想某处是僵局,但我无法找到。

对不起英语,当我尝试解释一些困难时,我仍然遇到问题。

Ste*_*ary 5

我一直在尝试对我的 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)