【发布时间】:2018-11-05 14:22:31
【问题描述】:
根据我阅读的 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;
}
}
}
【问题讨论】:
-
你试过 Run() 代替吗? Task.Run(() => ());
-
根据this documentation,
Task.Wait()only 让Task等待,仅此而已。您需要使用Task.Run()或Task.Start()。 -
另外,如果您不使用异步,则不需要任务或 CancellationToken。
-
@Tau,找到我之前看过的文档:blogs.msdn.microsoft.com/pfxteam/2009/10/15/…
-
@fstam,如果我先 Run() 任务,然后 Wait() 任务,在任务在其他线程上完成之前,我当前的代码不会阻塞吗?如果是这样,我想尽可能避免这种情况。