Dav*_*ten 3 c# task-parallel-library
根据我阅读的 Microsoft TPL 文档(链接),调用该Task.Wait()方法将阻塞当前线程,直到该任务完成(或取消或故障)。但它也表示,如果有问题的任务尚未启动,该Wait方法将尝试通过要求调度程序重新分配它在自己的线程上运行它,从而减少由于阻塞而造成的浪费量。
我有一个系统,其中任务(一旦运行)通过启动其他任务并等待它们的结果来收集数据。反过来,这些其他任务首先从其他任务中收集数据,并且非常强大,可能有几百层深。我真的不希望无数的任务阻塞并等待最后的一项任务最终完成。
但是,当我在测试控制台应用程序中尝试此操作时,Task.Wait()似乎根本没有启动任何东西。
构建一系列任务的正确咒语是什么,这些任务必须以最少的周期浪费相互等待?它有点像 ContinueWith,除了从系列中的最后一个任务开始......
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var source = new CancellationTokenSource();
var token = source.Token;
// Create a non-running task.
var task = new Task<string[]>(() => InternalCompute(token), token);
// Isn't this supposed to start the task?
task.Wait(CancellationToken.None);
// I realise this code now won't run until the task finishes,
// it's here for when I use task.Start() instead of task.Wait().
Console.WriteLine("Press any key to cancel the process.");
Console.ReadKey(true);
source.Cancel();
Console.WriteLine("Source cancelled...");
Console.WriteLine("Press any key to quit.");
Console.ReadKey(true);
}
private static string[] InternalCompute(CancellationToken token)
{
string[] data;
try
{
data = Compute(token);
}
catch (TaskCanceledException ex)
{
return null;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return new[] { ex.Message };
}
Console.WriteLine("Post-processor starting.");
for (int i = 0; i < data.Length; i++)
if (data[i] is null)
Console.WriteLine($"Null data at {i}.");
else
Console.WriteLine($"Valid data at {i}.");
Console.WriteLine("Post-processor completed.");
return data;
}
/// <summary>
/// This method stands in for an abstract one to be implemented by plug-in developers.
/// </summary>
private static string[] Compute(CancellationToken token)
{
var data = new string[10];
for (int i = 0; i < data.Length; i++)
{
token.ThrowIfCancellationRequested();
Thread.Sleep(250);
data[i] = i.ToString();
Console.WriteLine($"Computing item {i + 1}...");
}
return data;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Tasks 通常分为两组——“冷”任务和“热”任务。“冷”任务是尚未启动且不打算运行的任务。“热”任务是当前可能正在运行或可能未运行的任务,但重要的是,如果它们尚未运行,它们可能随时运行。他们的意思来运行,但尚未分配的资源(线程),他们需要这样做。
什么这篇文章讲的是执行一个“热”的任务,也没有以其他方式运行的机会。“热”任务是通过调用例如创建的Task.Run()。它们也是例如Task您将从异步方法接收到的s类型。new Task(...),另一方面给你“冷”任务。除非或直到您Start在该任务上调用或道德等效方法,否则它仍然是“冷的”。它显式调用其中一种方法,使其“热”而不是“冷”。
一般来说,这些天你根本不想处理“冷”任务,这就是为什么直接调用Task构造函数是不受欢迎的。在他们弄清楚调度应该如何真正工作之前,他们真的是一个糟糕的实验。大多数现代代码根本不希望处理“冷”任务。
上面帖子的关键引用是这个:
但是,如果它还没有开始执行,Wait 可能能够将目标任务从它排队的调度程序中拉出来,并在当前线程上内联执行它。
如果您没有调用Start该任务,则它没有与调度程序一起排队 - 所以显然我们不能做上面所说的。