C# 将ContinueWith与多个任务一起使用

C# 将ContinueWith与多个任务一起使用,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,这并不像我想象的那样,需要简单,启动一些任务来对一个对象执行操作。每个任务有一个唯一的对象。第二部分是在每个任务报告结果时与连续体。然而,我没有得到一个whalll类型的行为。希望有人能纠正我的错误 _tasks = new Task<AnalysisResultArgs>[_beansList.Count]; for (int loopCnt = 0; loopCnt < _beansList.Count; loopCnt++) { _tasks[loopCnt] =

这并不像我想象的那样,需要简单,启动一些任务来对一个对象执行操作。每个任务有一个唯一的对象。第二部分是在每个任务报告结果时与连续体。然而,我没有得到一个
whalll
类型的行为。希望有人能纠正我的错误

_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
}
\u tasks=新任务[\u beansList.Count];
对于(int loopCnt=0;loopCnt<\u beansList.Count;loopCnt++)
{
_tasks[loopCnt]=Task.Factory.StartNew(()=>
{
返回_beansList[loopCnt].Analyze(newBeanData);
});
等待任务[loopCnt]。继续(报告结果,
TaskContinuationOptions.RunContinuationsAsynchronously)
//完成所有任务后,进行一些内务管理
}
私有void报告结果(任务)
{
/*做一些串行操作
}
据我所知,将启动
\u beansList.Count
任务,并通过使用
ContinueWith
上的
等待
,在所有任务完成之前不会执行内务工作。我无法阻止,因为我需要确保能够限制传入的数据,以防止太多的任务等待执行


我在哪里搞砸了,等待实际上已经完成,而且内务管理也在运行,即使不是所有的任务都已运行到完成。

您不是在等待所有的任务,而是在循环中等待继续。您应该使用
Task.whalll
方法进行此操作。另外,如果可以在任务内部运行,为什么需要继续?将代码简化如下:

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);
private void ReportResults(AnalysisResultArgs结果)
{
/*做一些串行操作*/
}
...
_任务=新任务[_beansList.Count];
对于(int loopCnt=0;loopCnt<\u beansList.Count;loopCnt++)
{
var计数=loopCnt;
_任务[计数]=任务。运行(()=>
{
变量结果=_beansList[count]。分析(newbeansdata);
报告结果(结果);
返回结果;
});
}
//完成所有任务后,进行一些内务管理
等待任务。当所有(_任务);

您不是在等待所有任务,而是在循环中等待继续。您应该使用
Task.whalll
方法进行此操作。另外,如果可以在任务内部运行,为什么需要继续?将代码简化如下:

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);
private void ReportResults(AnalysisResultArgs结果)
{
/*做一些串行操作*/
}
...
_任务=新任务[_beansList.Count];
对于(int loopCnt=0;loopCnt<\u beansList.Count;loopCnt++)
{
var计数=loopCnt;
_任务[计数]=任务。运行(()=>
{
变量结果=_beansList[count]。分析(newbeansdata);
报告结果(结果);
返回结果;
});
}
//完成所有任务后,进行一些内务管理
等待任务。当所有(_任务);

正如@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());
    }
}
但是如果我们使用
Task.Run
启动
任务
,那么
async,wait
有助于释放调用线程池线程/同步上下文。它有助于提高系统的可伸缩性

  • 假定
    \u beansList
    List
    类型,但可根据实际需求进行修改
  • ReportResults
    可以修改为接受
    Func
    ,而不是简单的d
    任务
    ,从而在方法内部执行
    wait Func()
    ,然后调用代码可以真正异步,如下所示:

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

  • 正如@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());
        }
    }
    
    但是如果我们使用
    Task.Run
    启动
    任务
    ,那么
    async,wait
    有助于释放调用线程池线程/同步上下文。它有助于提高系统的可伸缩性

  • 假定
    \u beansList
    List
    类型,但可根据实际需求进行修改
  • ReportResults
    可以修改为接受
    Func
    ,而不是简单的d
    任务
    ,从而在方法内部执行
    wait Func()
    ,然后调用代码可以真正异步,如下所示:

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

  • 请减少到一个最小的例子是完整的,并再现问题。旁注:如果您使用
    Task.Run
    而不是
    StartNew
    ,使用
    wait
    而不是
    ContinueWith
    ,那么您的代码将更干净,表现更好。Stephen,我感谢您在这个问题上的评论和公认的权威,不过,这是一个最简单的示例,减去一些额外的类。你对Task.Run而不是StartNew的声明,使用Wait(我这么做了)而不是ContinueWith,我会看看我是否可以在网上搜索为什么这样更好。我认为ContinueWith就是这个意思,而wait就是它所说的。若要解释“开始一项新任务”,请在任务完成后继续执行第二步。等到所有的都完成了,这个例子还不完整。我无法将其粘贴到新项目中并在调试器中观察其行为。我在和上有博客帖子。@StephenCleary我有好几次这样的博客,他们帮了我很大的忙。不,您不能将其粘贴到项目中并单步执行。我为此道歉。尽管如此,您的评论和Thours的评论还是帮了大忙。请简化为一个完整的、再现问题的最小示例。旁注:如果您使用
    Task.Run
    而不是
    StartNew
    ,使用
    wait
    而不是
    ContinueWith
    ,那么您的代码将更干净,表现更好。Stephen,我感谢您的评论和记录