根据我阅读的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;
}
}
}
参考方案
Task
通常分为两类-“冷”任务和“热”任务。 “冷”任务是尚未启动且尚未运行的任务。 “热门”任务是当前可能正在运行或可能不在运行的任务,但重要的是,如果尚未运行,则它们可以随时运行。它们本来应该正在运行,但是尚未分配需要这样做的资源(线程)。
this post所说的是执行“热”任务,否则该任务没有机会运行。 “热”任务是通过调用Task.Run()
。他们也是您将从异步方法中收到的Task
的类型。另一方面,new Task(...)
为您提供“冷”任务。除非或直到您在该任务上调用Start
或道德等效方法,否则它将保持“冷”状态。它在显式调用这些方法之一,从而使其变得“热”而不是“冷”。
通常,您不希望一直都在使用“冷”任务,这就是为什么直接调用Task
构造函数的原因不胜枚举。从制定时间表应该如何工作之前,这确实是一个糟糕的实验。大多数现代代码根本不希望使用“冷”任务。
以上帖子的关键语录是这样的:
但是,如果尚未开始执行,则Wait可以将目标任务从排队的调度程序中拉出,并在当前线程上内联执行。
如果您尚未在任务上调用Start
,则说明该任务尚未与调度程序一起排队-因此,显然我们无法执行上述操作。
我有以下示例代码:static class Program { static void Main() { var cts = new CancellationTokenSource(); var task = Task.Factory.StartNew( () => { try { Console.WriteLine("Task: Runni…
当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…
改造正在返回一个空的响应主体 - java我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…
如何正确增加喜欢和不喜欢的人 - javascript我在每个帖子上都有一个按钮1)点赞按钮如果用户已经喜欢了该帖子,则显示“与众不同”按钮如果用户不喜欢该帖子,则为HTML部分<a href="javascript:void(0);" id="liker" data-count="0" data-fpc="481" data…
每个文件合并后添加换行 - python我有很多类似以下内容的JSON文件:例如。1.json{"name": "one", "description": "testDescription...", "comment": ""} test.json{"name"…