1

我有一个场景,其中我有多个函数要并行调用,并且我正在使用 TPL 来完成该任务。我用过

ConcurrentDictionary<string, List<result>> dictionary = new ConcurrentDictionary<string, List<result>>();

var tasks = Task.Run(()=>
{
  new Task(()=> {dictionary.TryAdd("First", CallFirstFunction());});
  new Task(()=> {dictionary.TryAdd("Second", CallSecondFunction());});
  new Task(()=> {dictionary.TryAdd("Third", CallThirdFunction());});
  new Task(()=> {dictionary.TryAdd("Fourth", CallFourthFunction());});
});

现在,我需要等到所有函数都执行完毕并在并发字典中返回一些结果,以便我可以将其用于进一步处理,但是如果某些返回的结果为空,无论任务顺序如何,我也想取消任何任务。如果任何函数返回空结果,我需要同时取消所有剩余的任务。我也检查了“CancellationToken”类,但我很困惑在任务中使用它以及如何在任务中共享函数状态。

任何帮助将不胜感激。此致

4

1 回答 1

0

要支持取消,您需要使用 CancellationTokenSource。请参阅https://msdn.microsoft.com/en-us/library/mt674886.aspx

您需要做的是将 传递CancellationTokenSource给您的方法,以便当结果为空时您可以调用CancellationTokenSource.Cancel()

async Task DoWorkAsync()
{
    var cts = new CancellationTokenSource();
    var ct = cts.Token;

    var tasks = new List<Task>
    {
        Task.Run(() => AddToDictionary("First", () => CallFirstFunction(), cts), ct),
        Task.Run(() => AddToDictionary("Second", () => CallSecondFunction(), cts), ct),
        Task.Run(() => AddToDictionary("Third", () => CallThirdFunction(), cts), ct),
        Task.Run(() => AddToDictionary("Fourth", () => CallFourthFunction(), cts), ct),
    };

    try
    {           
         await Task.WhenAll(tasks); 
    }
    catch (OperationCanceledException ex)
    {
    }
}

private void AddToDictionary(string key, Func<List<int>> method, CancellationTokenSource cts)
{
    if(cts.IsCancellationRequested)
        return;

    var result = method.Invoke();
    if(!result.Any());
        cts.Cancel();

    if(!cts.IsCancellationRequested)
        dictionary.TryAdd(key, result);
}

此示例假定您调用的操作(CallFirstFunction 等)不是异步的(不返回任务或任务)。否则,您也应该将其传递CancellationToken给他们并使用ct.ThrowIfCancellationRequested

取消任务会生成一个您需要处理的 OperationCanceledException。

当然,当任何方法在另一个方法返回空结果之前已经完成时,这些结果将已经存在于字典中。如果您需要其他行为,此示例将为您提供一些关于如何CancellationTokenSource与 Tasks 和 CancellationTokens 相关的基本概念

于 2016-05-17T14:49:40.827 回答