我有一项核心任务,即转发一些核心数据和多个其他子任务来获取额外数据。一旦核心任务和任何子任务准备好,就想对核心数据运行一些更丰富的过程。你知道怎么做吗?
想到这样的事情,但不确定它是做我想做的事情:
// Starting the tasks
var coreDataTask = new Task(...);
var extraDataTask1 = new Task(...);
var extraDataTask2 = new Task(...);
coreDataTask.Start();
extraDataTask1.Start();
extraDataTask2.Start();
// Enriching the results
Task.WaitAll(coreDataTask, extraDataTask1);
EnrichCore(coreDataTask.Results, extraDataTask1.Results);
Task.WaitAll(coreDataTask, extraDataTask2);
EnrichCore(coreDataTask.Results, extraDataTask2.Results);
另外考虑到在同一个核心对象上的丰富度,猜猜我需要把它锁定在哪里?
提前致谢!
答案 0 :(得分:4)
这是另一个利用Task.WhenAny()
来检测任务何时完成的想法。
对于这个最小的例子,我只假设核心数据和额外数据是字符串。但你可以调整你的类型。
另外,我实际上并没有进行任何处理。你必须插入你的处理。
另外,我正在做的一个假设,即不是很清楚,因为你大部分都试图并行化数据的收集,因为那是昂贵的部分,但是丰富的部分实际上非常快。基于该假设,您将注意到任务并行运行以收集核心数据和额外数据。但随着数据变得可用,核心数据会同步丰富,以避免因锁定而使代码复杂化。
如果你复制粘贴下面的代码,你应该可以按原样运行它,看看它是如何工作的。
public static void Main(string[] args)
{
StartWork().Wait();
}
private async static Task StartWork()
{
// start core and extra tasks
Task<string> coreDataTask = Task.Run(() => "core data" /* do something more complicated here */);
List<Task<string>> extraDataTaskList = new List<Task<string>>();
for (int i = 0; i < 10; i++)
{
int x = i;
extraDataTaskList.Add(Task.Run(() => "extra data " + x /* do something more complicated here */));
}
// wait for core data to be ready first.
StringBuilder coreData = new StringBuilder(await coreDataTask);
// enrich core as the extra data tasks complete.
while (extraDataTaskList.Count != 0)
{
Task<string> completedExtraDataTask = await Task.WhenAny(extraDataTaskList);
extraDataTaskList.Remove(completedExtraDataTask);
EnrichCore(coreData, await completedExtraDataTask);
}
Console.WriteLine(coreData.ToString());
}
private static void EnrichCore(StringBuilder coreData, string extraData)
{
coreData.Append(" enriched with ").Append(extraData);
}
编辑:.NET 4.0版
以下是我将如何为.NET 4.0更改它,同时仍保留相同的整体设计:
Task.Run()
变为Task.Factory.StartNew()
await
,而是调用Result
,这是一个等待任务完成的阻止调用。Task.WaitAny
代替Task.WhenAny
,这也是阻止来电。设计仍然非常相似。两个版本的代码之间的一个重要区别是,在.NET 4.5
版本中,只要有await
,当前线程就可以自由地执行其他工作。在.NET 4.0
版本中,无论何时调用Task.Result
或Task.WaitAny
,当前线程都会阻塞,直到任务完成。这种差异可能对你来说并不重要。但如果是,只需确保在后台线程或任务中包装并运行整个代码块以释放主线程。
另一个区别在于异常处理。对于.NET 4.5
版本,如果任何任务因未处理的异常而失败,则异常将以非常透明的方式自动解包和传播。使用.NET 4.0
版本,您将获得AggregateException
s,您必须自行解包和处理。如果这是一个问题,请确保事先进行测试,以便知道会发生什么。
就个人而言,我尽量避免Task.ContinueWith
。它往往会使代码变得非常丑陋且难以阅读。
public static void Main(string[] args)
{
// start core and extra tasks
Task<string> coreDataTask = Task.Factory.StartNew(() => "core data" /* do something more complicated here */);
List<Task<string>> extraDataTaskList = new List<Task<string>>();
for (int i = 0; i < 10; i++)
{
int x = i;
extraDataTaskList.Add(Task.Factory.StartNew(() => "extra data " + x /* do something more complicated here */));
}
// wait for core data to be ready first.
StringBuilder coreData = new StringBuilder(coreDataTask.Result);
// enrich core as the extra data tasks complete.
while (extraDataTaskList.Count != 0)
{
int indexOfCompletedTask = Task.WaitAny(extraDataTaskList.ToArray());
Task<string> completedExtraDataTask = extraDataTaskList[indexOfCompletedTask];
extraDataTaskList.Remove(completedExtraDataTask);
EnrichCore(coreData, completedExtraDataTask.Result);
}
Console.WriteLine(coreData.ToString());
}
private static void EnrichCore(StringBuilder coreData, string extraData)
{
coreData.Append(" enriched with ").Append(extraData);
}
答案 1 :(得分:0)
我认为你可能想要的是“ContinueWith”(文档在这里:https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx)。只要您的丰富不需要按特定顺序完成即可。
代码如下所示:
var coreTask = new Task<object>(() => { return null; });
var enrichTask1 = new Task<object>(() => { return null; });
var enrichTask2 = new Task<object>(() => { return null; });
coreTask.Start();
coreTask.Wait();
//Create your continue tasks here with the data you want.
enrichTask1.ContinueWith(task => {/*Do enriching here with task.Result*/});
//Start all enricher tasks here.
enrichTask1.Start();
//Wait for all the tasks to complete here.
Task.WaitAll(enrichTask1);
您仍然需要首先运行CoreTask,因为在完成所有丰富任务之前需要完成。但是从那里你可以开始所有任务,告诉他们什么时候完成“ContinueWith”做其他事情。
您还应该快速浏览一下“Enricher Pattern”,它可以帮助您实现您想要实现的目标(在线程之外)。例如:http://www.enterpriseintegrationpatterns.com/DataEnricher.html