C# 执行或不执行任务。如果任务不是';你还没跑吗?

C# 执行或不执行任务。如果任务不是';你还没跑吗?,c#,task-parallel-library,C#,Task Parallel Library,根据我阅读的Microsoft TPL文档()调用Task.Wait()方法将阻止当前线程,直到该任务完成(或取消,或出现故障)。但是它还说,如果所讨论的任务还没有启动,Wait方法将尝试在自己的线程上运行它,方法是请求调度程序重新分配它,从而减少由于阻塞而造成的浪费 我有一个系统,在这个系统中,任务(一旦运行)首先通过启动其他任务并等待结果来收集数据。这些其他任务依次从收集其他任务的数据开始,以此类推,可能有几百层的深度。我真的不希望无数的任务阻塞,等待最后一个任务最终完成 然而,当我在一个测

根据我阅读的Microsoft TPL文档()调用
Task.Wait()
方法将阻止当前线程,直到该任务完成(或取消,或出现故障)。但是它还说,如果所讨论的任务还没有启动,
Wait
方法将尝试在自己的线程上运行它,方法是请求调度程序重新分配它,从而减少由于阻塞而造成的浪费

我有一个系统,在这个系统中,任务(一旦运行)首先通过启动其他任务并等待结果来收集数据。这些其他任务依次从收集其他任务的数据开始,以此类推,可能有几百层的深度。我真的不希望无数的任务阻塞,等待最后一个任务最终完成

然而,当我在一个测试控制台应用程序中尝试这一点时,
Task.Wait()
似乎根本没有启动任何东西

构建一系列任务的正确咒语是什么?这些任务必须以最少的浪费周期相互等待?这有点像继续,除了从系列中的最后一个任务开始

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;
    }
  }
}
使用系统;
使用系统线程;
使用System.Threading.Tasks;
名称空间控制台EAPP1
{
班级计划
{
静态void Main(字符串[]参数)
{
var source=新的CancellationTokenSource();
var-token=source.token;
//创建一个非运行任务。
var任务=新任务(()=>InternalCompute(令牌),令牌);
//这不是要开始任务吗?
task.Wait(CancellationToken.None);
//我意识到这段代码在任务完成之前不会运行,
//当我使用task.Start()而不是task.Wait()时,它就在这里。
Console.WriteLine(“按任意键取消进程”);
Console.ReadKey(true);
source.Cancel();
Console.WriteLine(“源已取消…”);
控制台。WriteLine(“按任意键退出”);
Console.ReadKey(true);
}
私有静态字符串[]InternalCompute(CancellationToken令牌)
{
字符串[]数据;
尝试
{
数据=计算(令牌);
}
捕获(TaskCanceledException ex)
{
返回null;
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
返回新的[]{ex.Message};
}
Console.WriteLine(“后处理器启动”);
for(int i=0;i
任务
通常分为两组——“冷”任务和“热”任务。“冷”任务是指尚未启动且不打算运行的任务。“热”任务是指当前正在运行或未运行的任务,但重要的是,如果它们尚未运行,则可以随时运行。它们本应运行,但尚未分配执行此操作所需的资源(线程)

我们谈论的是执行一个“热门”任务,否则就没有机会运行它。“热”任务是通过调用例如
Task.Run()
创建的。例如,它们也是从异步方法接收的
任务的类型<代码>新任务(…)
,另一方面,它会为您提供“冷”任务。除非或直到您对该任务调用
Start
或道德等效方法,否则它将保持“冷”。它显式地调用其中一个方法,使其成为“热”而不是“冷”

通常,您不希望在所有这些天都在处理“冷”任务,这就是为什么直接调用
Task
构造函数是不受欢迎的。在他们研究出日程安排应该如何真正起作用之前,他们真的是一个糟糕的实验。大多数现代代码根本不希望处理“冷”任务

上述帖子的关键引语如下:

但是,如果Wait尚未开始执行,它可能能够将目标任务从其排队的调度程序中拉出,并在当前线程上内联执行

如果您没有对任务调用
Start
,则该任务没有与调度程序一起排队-因此显然我们无法执行上面所述的操作。

这是导致混乱的部分原因(重点已添加)

如果等待的任务已开始执行,则必须阻止等待。但是,如果Wait尚未开始执行,它可能能够将目标任务从其排队的调度程序中拉出,并在当前线程上内联执行

以下是该方法的说明:

启动
任务
,将其调度到当前的
任务调度程序

这些是任务生命周期的关键:

public enum TaskStatus
{
    Created = 0, // The task has been initialized but has not yet been scheduled.
    WaitingForActivation = 1, // The task is waiting to be activated and scheduled internally by the .NET Framework infrastructure.
    WaitingToRun = 2, // The task has been scheduled for execution but has not yet begun executing.
    Running = 3, // The task is running but has not yet completed.
    WaitingForChildrenToComplete = 4, // The task has finished executing and is implicitly waiting for attached child tasks to complete.
    RanToCompletion = 5, // The task completed execution successfully.
    Canceled = 6, // The task acknowledged cancellation by throwing an OperationCanceledException with its own CancellationToken while the token was in signaled state, or the task's CancellationToken was already signaled before the task started executing.
    Faulted = 7 // The task completed due to an unhandled exception.
}
本文含蓄地讨论了hot处于
WaitingForActivation
WaitingToRun
阶段的任务,并解释了在调用
Wait
方法时,在哪些条件下可以在内部将这些任务推进到
Running
阶段。它不是在
创建
阶段谈论任务。如果未调用其
Start
RunSynchronously
方法,则此阶段中的任务无法进行。换句话说,.NET基础设施从不自动将任务的温度从冷变热