简体   繁体   English

为什么并行任务不运行?

[英]Why are parallel tasks not running?

I have this code, it is the skeleton of larger functionality stripped down to prove the problem:我有这段代码,它是为了证明问题而剥离的更大功能的骨架:

        var tasks = Enumerable.Range(0, 10)
            .Select(laneNo => Task.Run(() => Console.WriteLine($"Starting generator for lane {laneNo}")));

        for(int r=0; ;++r)
        {
            Task.Delay(TimeSpan.FromSeconds(3)).Wait();

            Console.WriteLine($"Iteration {r} at {DateTime.Now}");
        }

I never see "Starting generator" printed to Console but I do see the iteration fire every 3 seconds - something is causing those tasks not to progress (in the real code they run for a significant period but removing that doesn't affect the problem).我从来没有看到“启动生成器”打印到控制台,但我确实看到迭代每 3 秒触发一次 - 某些原因导致这些任务无法进行(在实际代码中它们运行了很长一段时间,但删除它不会影响问题) .

Why are the first bunch of Tasks not running?为什么第一批任务没有运行? My theory is it's related to Task.Delay ?我的理论是它与Task.Delay有关吗?

Your linq-statment is never materialized.您的 linq-statment 永远不会实现。 Linq-operators like Select, Where, OrderBy, etc work as building blocks that you chain together but they are not executed until you run it through a foreach or use operators which do not return enumerables, like ToArray, ToList, First, Last etc. Linq 运算符,如 Select、Where、OrderBy 等,它们作为构建块链接在一起,但在您通过 foreach 运行它或使用不返回可枚举的运算符(如 ToArray、ToList、First、Last 等)之前,它们不会执行。

If you call ToList at the end you should see all of the tasks executing but if you only call First you should see only a single one because the iteration of your original Range will then terminate after first element.如果您在最后调用 ToList,您应该会看到所有正在执行的任务,但如果您只调用 First,您应该只会看到一个,因为原始 Range 的迭代将在第一个元素之后终止。

LINQ Select has deferred execution; LINQ Select已延迟执行; it simply defines an iterator, so your Task s are not being generated.它只是定义了一个迭代器,因此不会生成您的Task

You could make use of Task.WhenAll(IEnumerable<Task>) , which will iterate and await each Task , generating new Task that completes once all the provided tasks have also completed:您可以使用Task.WhenAll(IEnumerable<Task>) ,它将迭代并等待每个Task ,生成新的Task一旦所有提供的任务也完成后完成:

var tasks = Enumerable.Range(0, 10)
        .Select(laneNo => Task.Run(() => Console.WriteLine($"Starting generator for lane {laneNo}")));

await Task.WhenAll(tasks);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM