根据我阅读的 Microsoft TPL 文档 (link),调用 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;
}
}
}
最佳答案
任务
通常分为两组 - “冷”任务和“热”任务。 “冷”任务是尚未开始的任务,还不打算运行。 “热”任务是当前可能正在运行或未运行的任务,但重要的是,如果它们尚未运行,则它们可能随时运行。它们意味着正在运行,但尚未为其分配运行所需的资源(线程)。
什么 this post正在谈论正在执行一个没有机会运行的“热”任务。 “热”任务是通过调用例如创建的任务.运行()
。他们也是例如您将从异步方法接收到的 Task
的类型。另一方面,new Task(...)
为您提供“冷”任务。除非或直到您对该任务调用 Start
或道德上等效的方法,否则它将保持“冷”状态。它显式调用其中一种方法,使其“热”而不是“冷”。
通常,这些天您不想一直处理“冷”任务,这就是为什么不赞成直接调用 Task
构造函数的原因。在他们弄清楚调度应该如何真正起作用之前,他们确实是一个糟糕的实验。大多数现代代码根本不希望处理“冷”任务。
上面帖子的关键引用是:
However, if it hasn’t started executing, Wait may be able to pull the target task out of the scheduler to which it was queued and execute it inline on the current thread.
如果您没有在任务上调用 Start
,则它还没有与调度程序一起排队 - 所以显然我们不能执行上述操作。
关于c# - 如果 Task.Wait 尚未运行,它是否会启动任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53156253/