【问题标题】:Multiple Task Continuation - wait until all complete多任务继续 - 等到全部完成
【发布时间】:2018-11-01 18:11:39
【问题描述】:

我有以下一段代码,我首先运行查询并添加原始结果ViewModel.RawContracts.AddRange(contractResults);

然后我想用多个不同的数据源来丰富这组数据,例如_enrichmentHelper.ResolveSecurities(token, contractsToEnrich); 这些方法中的所有扩充本身都是异步完成的。

完成所有这些丰富后,我想运行最后一段代码来获取现在丰富的原始数据,并将其添加到我的网格ViewModel.ContractRows.AddRange(ViewModel.RawContracts);

但是,我的最终继续 queryAndEnrichmentTask 在查询任务完成后执行,而不是在每个扩充继续完成之后执行。

我在这里做错了什么?

Task.Factory.StartNew
(
    () =>
    {
        Log.Debug("Starting getting contracts");
        Task queryTask = _serviceModel.GetContractsByCriteriaAsync(token, ViewModel.QueryRequest)
            .LogExceptions()
            .ContinueWith
            (
                prevTask =>
                {
                    if (!token.IsCancellationRequested)
                    {
                        IQueryResponse response = null;
                        Log.Debug("Received contract response.");

                        if (prevTask.IsFaulted || (response = prevTask.Result) == null)
                        {
                            ViewModel.ErrorMessage = "Failed to load contracts. Please check the log file for details.";
                        }
                        else
                        {
                            if (response.Contracts != null)
                            {
                                Log.Debug($"Start loading {response.Contracts.Count()} contract positions...");

                                bool successful = true; 

                                if (successful && prevTask.IsCompleted && prevTask.Result != null)
                                {
                                    contractResults = prevTask.Result.Contracts.ToList();
                                    ViewModel.RawContracts.Clear();
                                    ViewModel.RawContracts.AddRange(contractResults);
                                }
                                Log.Debug("Finished loading contracts");
                            }
                        }
                    }
                    Log.Debug("Finished loading contracts");

                }, token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default
            ); // End add raw results task

            IList<IContract> contractsToEnrich = ViewModel.RawContracts;

            queryTask.ContinueWith(prevTask =>
            {
                _enrichmentHelper.ResolveSecurities(token, contractsToEnrich);
            }, token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);

            queryTask.ContinueWith(prevTask =>
            {
                _enrichmentHelper.ResolveBooks(token, contractsToEnrich);
            }, token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);

            queryTask.ContinueWith(prevTask =>
            {
                _enrichmentHelper.ResolveCounterparties(token, contractsToEnrich);
            }, token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);

            queryTask.ContinueWith(prevTask =>
            {
                _enrichmentHelper.ResolveLegalEntities(token, contractsToEnrich);
            }, token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
    }, token
)
.LogExceptions()
.ContinueWith
(
    queryAndEnrichmentTask =>
    {
        Log.Debug("Post search task started");

        if (queryAndEnrichmentTask.IsFaulted)
        {
            if (!ViewModel.HasErrorMessage)
                ViewModel.ErrorMessage = "Error occured when loading data. Please refer to log file for details";
        }
        else
        {
            ViewModel.ContractRows.AddRange(ViewModel.RawContracts);
        }
        Log.Debug("Post search task completed");
    }, token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default)
.LogExceptions();

【问题讨论】:

  • 你应该很少使用ContinueWith。使用await 为任务添加延续。正确编写更容易,并且使您很难诊断代码中的错误的可能性大大降低。在极少数情况下,ContinueWith 是需要或可取的。
  • 不同意从不使用ContinueWith。使用您的团队、正在使用的库和/或您自己的经验定义的约定。

标签: c# task-parallel-library


【解决方案1】:

您在外部任务中创建queryTask,但从不等待它。外部任务将在 queryTask 完成之前返回。外层任务上的ContinueWith()会在外层任务返回时运行,不会等待queryTask完成。

最小的解决方法是在结束包含它的任务块之前等待queryTask。外部任务仍将返回,但其 Task 将设置为未完成状态,允许 ContinueWith() 通过等待它然后继续来完成其工作。

    await queryTask;  //<-- add this
)
.LogExceptions()
.ContinueWith
(
    queryAndEnrichmentTask =>

【讨论】:

    猜你喜欢
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    相关资源
    最近更新 更多