首页 > 解决方案 > TaskCompletionSource 执行缓慢

问题描述

通过在同步方法中循环多个TaskCompletionSource实例,超过5个程序执行起来会变慢,但是在异步方法中就没有这个问题了。

这是有问题的代码 使用同步方式,执行变慢,1秒左右创建一个

Parallel.For(1, 100, (index) =>
{
    System.Console.WriteLine("start:");
    var t = new TaskCompletionSource<string>();
    count++;

    System.Console.WriteLine("end:" + count + "\n");
    t.Task.Wait();
    System.Console.WriteLine("ended:");
});

这是没有问题的代码,执行非常快

Parallel.For(1, 100, async (index) =>
{
    System.Console.WriteLine("start:");
    var t = new TaskCompletionSource<string>();
    count++;

    System.Console.WriteLine("end:" + count + "\n");
    await t.Task;
    System.Console.WriteLine("ended:");
});

标签: c#.nettaskcompletionsource

解决方案


你对 有一些误解Parallel.For()

首先,Parallel.For()不是为异步任务设计的。许多帖子中已经提到过:

想象一下,在厨房里,你有 5 个厨师(线程),Parallel.For()正在将每个待处理的菜一个一个地分配给每个厨师,直截了当。但是async-await,正在分配“承诺我会做一道菜的协议”来做饭,这是一个约会,只有线程启动它并“完成”这个过程。

这就是为什么您在async-await示例中得到非常快速的响应的原因。但是这一行:

System.Console.WriteLine("ended:");

不打印。当工作线程遇到 时await,此任务结束。


让我们简化您正在使用的示例,这不是测试andTaskCompletionSource之间差异的好示例。async-awaitParallel.For()

//Async
Parallel.For(1, 100, async (index) =>
{
    System.Console.WriteLine("start:" + index);
    await Task.Delay(1000);
    System.Console.WriteLine("ended:" + index);
});
//Task.Delay(2000).Wait();

Async-awaitended: index在这种情况下永远不会打印。尝试Task.Delay(2000).Wait();在末尾添加一行,您可以注意到ended:index最终打印出来了。

尝试减少1000延迟1,它可能会打印一些ended但它不能保证Parallel.for这意味着你的任务根本不会在Parallel.for()线程内等待,它由另一个线程持有async-await

//Sync

Parallel.For(1, 100, (index) =>
{
    System.Console.WriteLine("start:" + index);
    Task.Delay(1000).Wait();
    System.Console.WriteLine("ended:" + index);
});

并行怎么样,是的,它很“慢”,启动线程和任务调度程序需要成本。但这确实是在告诉您任务在程序结束之前完成。


推荐阅读