【问题标题】:Task execution dependent upon the waiting mechanism?任务执行依赖于等待机制?
【发布时间】:2019-09-08 02:28:15
【问题描述】:

这是我正在运行的伪代码:

变体 #1:

List<Task> tasks = new List<Task>();
foreach (...)
{
    Task task = Task.Run(() =>
    {
        doWork();
    });
    tasks.Add(task);
}

Task.WhenAll(tasks.AsParallel()).ContinueWith((t) =>
{
    // process results/handle errors
    ...
});

变体 #2:

List<Task> tasks = new List<Task>();
foreach (...)
{
    Task task = Task.Run(() =>
    {
        doWork();
    });
    tasks.Add(task);
}

Task.WhenAll(tasks.AsParallel()).Wait();

// process results/handle errors
...

我的问题是,为什么调用doWork 的方式在#1 和#2 之间出现根本不同?这是设计使然,我只是不明白这应该如何工作?

我(显然失败)的理解/假设是,doWork 将以多线程/异步方式调用,如果可用则并行,两种场景,唯一的区别是调用代码会以不同的方式等待完成。但是任务的实际执行方式是相同的,因为它们的计划/“运行”方式相同。

但从调试两个版本的代码后我可以看出,变体 #1 导致 doWork 以真正的并行/完全多线程方式调用,而变体 #2 似乎表现得像一个单一的-每个任务的线程化、顺序执行。

我错过了什么?

【问题讨论】:

  • 首先摆脱AsParallel,这不属于这里。 WhenAll 采用 IEnumerable 或数组。然后看看这个:stackoverflow.com/a/41953073/224370
  • 如何等待Task.WhenAll() 在变体 #1 中完成?我知道ContinueWith() 只会在那时执行,但是您如何阻止您的应用程序/方法退出?
  • @IanMercer - 感谢您对其他答案的引用;关于它在同一线程上运行(同步时)的部分实际上回答了我的问题。 Wait 的文档只是说“等待任务完成执行”,并没有提及单线程与多线程的任何内容......
  • @sellotape,我根本没有在那儿等,我已经将所有结果处理代码移到 ContinueWith 处理程序的主体中。

标签: c# multithreading plinq


【解决方案1】:

.AsParallel()LINQ多线程扩展,与Task无关。 Task.Run(...) 本身对于大多数情况来说已经足够了,可以使用或不使用LINQ

混合使用AsParallel()Task.Run() 是危险的事情,除非您确定自己在做什么:如果不努力,它可能会显着降低您的性能,而不是像您期望的那样让它变得更好。

最后,不要Wait()Task:它将以常规同步方式强制执行,从而取消Task的所有好处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多