在ActionBlock中等待所有任务完成的任何方法?

时间:2015-10-22 06:06:53

标签: c# task-parallel-library tpl-dataflow

首先,让我描述一下我正在编写的程序的流程。

GUI中有一个对象列表,当用户单击一个对象时,将从磁盘读取对象数据并加载。这可能需要大约3-4秒。

假设用户不耐烦并在第一个对象仍在加载时点击另一个对象。程序将加载第二个对象,同时取消第一个对象的加载。

由于用户可以在其中任何一个成功完成之前进行垃圾邮件加载操作,因此我实施了一个操作块来排队所有加载操作。

所以我有一个这样的动作块:

this.loadObjectActionBlock = new ActionBlock<CaseObject>(
    c => this.LoadCaseData(CaseObject),
    new ExecutionDataflowBlockOptions()
    {
        MaxDegreeOfParallelism = 10,
    });

每次用户点击Case对象时,我都会调用:

this.loadObjectActionBlock.Post(CaseObject);

CaseObject将由我定义的函数处理:

private void LoadCaseData(CaseObject caseObject)
    {
        caseObject.LoadCaseData();          
    }

我现在需要做的是,我需要等到所有CaseObjects都被加载,以便我可以继续我的代码。

我已经尝试通过调用

来检测所有案例的处理时间
if (this.loadObjectActionBlock.InputCount == 0)
{
    this.loadObjectActionBlock.Complete();
}

caseObject.LoadCaseData();之后但是当加载动作发生得太快并且动作块被告知不再接受任何输入时,这会导致奇怪的结果。如果我理解正确,InputCount属性只会查看队列中剩余的作业数。

所以我想做的是我想等待ActionBlock:

await this.loadObjectActionBlock.Completion;

队列中的所有内容都已完全处理完毕。

我可能没有像往常一样使用ActionBlock,所以如果有任何替代方案,请提出我可以阅读的任何建议。

TLDR:我想同时处理多个任务(由用户启动)并等待所有任务完成,然后执行单个任务。

提前致谢:)

1 个答案:

答案 0 :(得分:1)

  

程序将加载第二个对象,同时取消第一个对象的加载。

队列不适合此行为,特别是因为TPL块只能完成一次。

如果要实现此行为,只需确保在继续下一个操作之前遵循取消令牌:

private static void ProcessCase(CaseObject caseObject, CancellationToken token)
{
  caseObject.LoadCaseData();
  token.ThrowIfCancellationRequested();
  ... // Further processing goes here
}

从UI线程调用:

static CancellationTokenSource _cts;
private static async Task ProcessCaseAsync(CaseObject caseObject)
{
  if (_cts != null)
    _cts.Cancel();
  _cts = new CancellationTokenSource();
  await Task.Run(() => ProcessCase(caseObject, _cts.Token));
}