将ContinueWith用于多个任务

时间:2017-05-12 04:29:55

标签: c# async-await task-parallel-library

这并不像我认为的那样需要很简单,启动一些任务来对对象进行操作。每个任务一个唯一的对象。当每个任务报告结果时,第二部分是ContinueWith。但是,我没有得到WhenAll类型的行为。希望有人可以让我直截了当。

_tasks = new Task<AnalysisResultArgs>[_beansList.Count];
for (int loopCnt = 0; loopCnt < _beansList.Count; loopCnt++)
{
    _tasks[loopCnt] = Task<AnalysisResultArgs>.Factory.StartNew(() =>
    {
        return _beansList[loopCnt].Analyze(newBeanData);
    });
    await _tasks[loopCnt].ContinueWith(ReportResults, 
                  TaskContinuationOptions.RunContinuationsAsynchronously)  
    // do some housekeeping when all tasks are complete          
}

private void ReportResults(Task<AnalysisResultArgs> task)
{
     /* Do some serial operations
}

我的理解是,_beansList.Count任务将会启动,并且await上的ContinueWith将执行内务工作,直到所有任务完成为止。我无法阻止,因为我需要确保能够限制传入的数据以防止太多的任务等待执行。

我在哪里,等待实际完成,并且即使并非所有任务都已完成,家务也会运行。

2 个答案:

答案 0 :(得分:2)

您没有等待所有任务,等待循环继续。您应该使用Task.WhenAll方法。另外,如果你可以在任务中运行它,为什么还需要延续?像这样简化您的代码:

private void ReportResults(AnalysisResultArgs results)
{
     /* Do some serial operations */
}

...
_tasks = new Task<AnalysisResultArgs>[_beansList.Count];
for (int loopCnt = 0; loopCnt < _beansList.Count; loopCnt++)
{
    var count = loopCnt;
    _tasks[count] = Task.Run(() =>
    {
        var results = _beansList[count].Analyze(newBeanData);
        ReportResults(results);
        return results;
    });
}

// do some housekeeping when all tasks are complete          
await Task.WhenAll(_tasks);

答案 1 :(得分:1)

正如@Stephen已经提到的,问题中的代码不是最小的,完整的和可验证的。我冒昧地做了一些假设,这就是我认为你的代码应该是这样的:

public async Task<AnalysisResultArgs[]> MainMethod()
{
    var _beansList = new List<AnalysisResultArgs>();

    for(int i=0; i< 99; i++) // Considering 100 records
        _beansList.Add(new AnalysisResultArgs());

    var _tasks = new Task<AnalysisResultArgs>[_beansList.Count];

    for (int loopCnt = 0; loopCnt < _beansList.Count; loopCnt++)
    {
        var local = loopCnt;
        _tasks[local] = Task.Run(async() => await ReportResults(_beansList[local].Analyze(new AnalysisResultArgs())));
    }

    return await Task.WhenAll(_tasks);
}

private async Task<AnalysisResultArgs> ReportResults(Task<AnalysisResultArgs> task)
{
    await Task.Delay(1000);
    return await Task.FromResult(new AnalysisResultArgs());
}

public class AnalysisResultArgs
{   
    public async Task<AnalysisResultArgs> Analyze(AnalysisResultArgs newBeanData)
    {
        await Task.Delay(1000);
        return await Task.FromResult(new AnalysisResultArgs());
    }
}

假设/其他细节:

  1. Task.DelayTask.FromResult仅仅是实际逻辑的持有者。
  2. 来电AnalyzeReportResults中的所有方法均为Async
  3. 在循环代码中可能是:

    _tasks[local] = ReportResults(_beansList[local].Analyze(new 
             AnalysisResultArgs()));
    
  4. 但是如果我们使用Task.Run来启动Task,那么async, await有助于释放调用线程池线程/同步上下文。它有助于提高系统的可扩展性。

    1. 假设_beansList属于List<AnalysisResultArgs>类型,但可以根据实际需求进行修改
    2. 可以修改
    3. ReportResults以获取Func<Task<AnalysisResultArgs>> func,而不是简单的d Task<AnalysisResultArgs>,从而在方法中执行await func(),然后调用代码可以真是异步如下:

        _tasks[local] = Task.Run(async() => await ReportResults(async() => await 
        _beansList[local].Analyze(new AnalysisResultArgs())));