c# - 如果 Task.Wait 尚未运行,它是否会启动任务?

标签 c# task-parallel-library

根据我阅读的 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/

相关文章:

c# - 我可以避免存储 MS Exchange 凭据,同时仍然能够进行身份验证(针对 EWS)吗?

c# - 在 C# 中的文本框中显示运行日期和时间

c# - TableLayoutPanel 在列内放置标签控件

c# - 使用 c# 2010 express 连接到 oracle XE

c# - 如何在 SQL 选择期间通过 LINQ 数据上下文将 INT32 转换为 INT?

c# - 当 ContinueWith 与 System.Threading.Tasks.Task 一起使用时,单元测试失败

c# - Parallel.ForEach 与异步 lambda 等待所有迭代完成

c# - 在任务并行库场景中按正确顺序记录

c# - 如何处理任务并行库中的目录文件?

f# - 在 F# 中使用 Task.WhenAll 重写 C# 代码