C# TaskCompletionSource执行缓慢

C# TaskCompletionSource执行缓慢,c#,.net,taskcompletionsource,C#,.net,Taskcompletionsource,通过在同步方法中循环多个TaskCompletionSource实例,超过5个程序的执行速度会变慢,但在异步方法中,您没有这个问题 这是使用同步方法的问题代码,执行速度变慢,大约在1秒内创建一个 Parallel.For(1, 100, (index) => { System.Console.WriteLine("start:"); var t = new TaskCompletionSource<string>(); count++; Sys

通过在同步方法中循环多个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(1100,(索引)=>
{
System.Console.WriteLine(“开始:”);
var t=new TaskCompletionSource();
计数++;
System.Console.WriteLine(“结束:“+count+”\n”);
t、 Task.Wait();
System.Console.WriteLine(“结束:”);
});
这是没有问题的代码,执行速度非常快

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:");
});
Parallel.For(1100,异步(索引)=>
{
System.Console.WriteLine(“开始:”);
var t=new TaskCompletionSource();
计数++;
System.Console.WriteLine(“结束:“+count+”\n”);
等待任务;
System.Console.WriteLine(“结束:”);
});

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

首先,
Parallel.For()
不是为异步任务设计的。很多帖子都提到了这一点:

想象一下,在厨房里,你有5个厨师(线程),
并行。For()
直接将每个待处理的菜一个接一个地分配给每个厨师。但是async await正在指定“约定我会做一道菜”来做饭,这是一个只有预约的线程启动它并“完成”这个过程

这就是为什么在
asyncwait
示例中得到非常快的响应。但这句话:

System.Console.WriteLine("ended:");
没有打印。当工作线程遇到
等待
时,此任务结束


让我们简化您正在使用的示例,
TaskCompletionSource
不是测试
async wait
Parallel.for()之间差异的好例子

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

尝试在延迟中将
1000
减少到
1
,它可能会打印一些
结束的
,但不能通过
并行来保证。对于
,这意味着您的任务根本没有在
并行中等待。对于()
线程,它被另一个线程持有,用于
异步等待

//Sync

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

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

这对您来说可能很有趣TaskCompletionSource并不慢。它一点也不跑。它提供了一个任务,当其他一些代码调用
.SetResult
时,可以切换该任务的状态。没有代码向代码中的TCS发送信号,因此它永远不会完成第二个代码段就是实际的bug。它不会并行地等待任何事情,它会触发100个任务,并且从不等待它们。这100个任务仍然被阻止,并且永远不会打印
结束:
对不起,我没有清楚地描述问题。上面是我写的伪代码。我只想还原并发场景。我不需要等待输出“结束”,通过同步方法调用并创建TaskCompletionSource实例。在并发的情况下,创建超过我的CPU核心号的实例会很慢,我已经尝试设置ThreadPool.SetMinThreads(100100);但这根本不能解决问题。如果任务根本没有等待,那么应该立即打印“ended..”,或者您的意思是
并行。对于
任务?@Rekshino,我调整了措辞,抱歉搞混了。@Rekshino MatrixTai的解释是正确的<代码>结束:
仅在TCS发出信号时运行,而TCS从未发出信号。OP的第二个代码段将启动100个任务,每次4个或8个(取决于内核的数量),并且从不等待它们。它几乎马上就要结束了。当任务到达
等待t任务时,任务本身将停止和永不打印
结束:
@PanagiotisKanavos他的答案部分正确。Async Wait one永远不会打印ended:index,这意味着您的任务在Parallel中根本不会被等待。for()作用域引用了他的代码段,这是错误的。如果我们在
Parallel.For
循环外等待,它将打印“end”。因此,在MatrixTai的异步代码中,内部
并行。对于
我们将等待并打印“结束”,外部我们不等待。@Rekshino,
等待
不是
等待()
,如果内部
等待()
,则它不再是异步的,而是同步作业,这就是同步示例
wait
Parallel中。for()
只是指
完成后回到这里
,但这没有意义,因为
Parallel.for
在启动所有任务后结束。如果要使用
async wait
,只需将
for循环
Task.WaitAll/WhenAll
一起使用即可。
//Sync

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