如果 Task.Wait 尚未运行,它是否或不启动任务? [英] Does or does Task.Wait not start the task if it isn't already running?

查看:29
本文介绍了如果 Task.Wait 尚未运行,它是否或不启动任务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据我阅读的 Microsoft TPL 文档(link) 调用 Task.Wait() 方法将阻塞当前线程,直到该任务完成(或取消或故障).但它也说如果有问题的任务还没有开始,Wait 方法将尝试通过要求调度程序重新分配它来在自己的线程上运行它,从而减少因阻塞造成的浪费.

According to the Microsoft TPL documentation I read (link) calling the Task.Wait() method will block the current thread until that task finishes (or cancels, or faults). But it also said that if the task in question hadn't started yet, the Wait method will attempt to run it on its own thread by asking the scheduler to reassign it, thus reducing the amount of wastage due to blocking.

我有一个系统,其中任务(一旦运行)通过启动其他任务并等待它们的结果来收集数据.反过来,这些其他任务首先从其他任务中收集数据,并且非常强大,可能有几百层深.我真的不想让无数的任务阻塞并等待最后的一个任务最终完成.

I've got a system in which tasks (once running) begin by collecting data by starting other tasks and waiting on their results. These other tasks in turn begin by collecting data from yet other tasks and-so-on-and-so-fort, potentially a few hundred layers deep. I really don't want umpteen tasks blocking and waiting for the one task at the end to finally finish.

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

However when I tried this out in a test console app, Task.Wait() doesn't seem to start anything at all.

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

What are the correct incantations for building a sequence of tasks that must all wait on each other with a minimum of wasted cycles? It's sort of like ContinueWith, except starting with the last task in the series...

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;
    }
  }
}

推荐答案

Task 通常分为两组——冷"任务和热"任务.冷"任务是尚未启动且尚未运行的任务.热"任务是当前可能正在运行或可能未运行的任务,但重要的是,如果它们尚未运行,它们可能随时运行.它们意味着正在运行,但尚未分配到所需的资源(线程).

Tasks are generally split into two groups - "cold" tasks and "hot" tasks. "cold" tasks are tasks that have not yet been started and are not meant to run yet. "hot" tasks are tasks that may or may not be currently running but, importantly, if they're not running yet, they may do so at any time. They're meant to be running but haven't yet been assigned the resource (a thread) they need to do so.

什么这篇文章正在谈论的是执行一个没有机会运行的热"任务.热"任务是通过调用创建的,例如Task.Run().他们也例如您将从异步方法接收到的 Task 类型.new Task(...),另一方面给你冷"任务.除非或直到您对该任务调用 Start 或道德等效方法,否则它保持冷".它显式调用其中一种方法,使其热"而不是冷".

What this post is talking about is executing a "hot" task that hasn't otherwise had an opportunity to run. "hot" tasks are created by calling e.g. Task.Run(). They're also e.g. the type of Tasks you'll receive from async methods. new Task(...), on the other hand gives you "cold" tasks. Unless or until you call Start or moral equivalent methods on that task, it remains "cold". It's calling one of those methods explicitly that makes it "hot" instead of "cold".

一般来说,这些天你不想处理冷"任务,这就是为什么直接调用 Task 构造函数是不受欢迎的.在他们弄清楚调度应该如何真正工作之前,他们真的是一个糟糕的实验.大多数现代代码根本不希望处理冷"任务.

Generally, you don't want to be working with "cold" tasks at all these days, which is why directly calling a Task constructor is frowned upon. They were really a bad experiment from before they worked out how scheduling should really work. Most modern code doesn't expect to be working with "cold" tasks at all.

以上帖子的关键引用是这个:

The key quote from the above post is this one:

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

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,它就没有被调度程序排队 - 所以显然我们不能做上面所说的.

If you've not called Start on the task, it hasn't been queued with a scheduler - so obviously we cannot do what the above says.

这篇关于如果 Task.Wait 尚未运行,它是否或不启动任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆