C# 有没有办法在ActionBlock中等待所有任务完成?

C# 有没有办法在ActionBlock中等待所有任务完成?,c#,task-parallel-library,tpl-dataflow,C#,Task Parallel Library,Tpl Dataflow,首先,让我描述一下我正在编写的程序的流程 GUI中有一个对象列表,当用户单击其中一个时,对象数据从磁盘读取并加载。这可能需要大约3-4秒 假设用户不耐烦,在第一个对象仍在加载时单击另一个对象。程序将加载第二个对象,同时取消第一个对象的加载 由于用户可以在任何加载操作成功完成之前发送垃圾邮件,因此我实现了一个操作块来排队所有加载操作 所以我有一个像这样的动作块: this.loadObjectActionBlock = new ActionBlock<CaseObject>(

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

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

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

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

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

this.loadObjectActionBlock = new ActionBlock<CaseObject>(
    c => this.LoadCaseData(CaseObject),
    new ExecutionDataflowBlockOptions()
    {
        MaxDegreeOfParallelism = 10,
    });
private void LoadCaseData(CaseObject caseObject)
    {
        caseObject.LoadCaseData();          
    }
CaseObject将由我定义的函数处理,如下所示:

this.loadObjectActionBlock = new ActionBlock<CaseObject>(
    c => this.LoadCaseData(CaseObject),
    new ExecutionDataflowBlockOptions()
    {
        MaxDegreeOfParallelism = 10,
    });
private void LoadCaseData(CaseObject caseObject)
    {
        caseObject.LoadCaseData();          
    }
我现在需要做的是,我需要等待所有CaseObject加载完毕,以便在加载之后继续编写代码

我曾尝试通过呼叫来检测何时处理所有案件

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

所以我想做的是等待ActionBlock,比如:

await this.loadObjectActionBlock.Completion;
当队列中的所有内容都已完全处理时

我可能没有按照预期使用ActionBlock,因此如果在这方面有任何替代方案,请提出任何我可以阅读的建议

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

提前感谢:)

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

队列不是这种行为的合适解决方案,特别是因为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));
}

谢谢你的回复。取消位现在不是问题,因为我在ProcessCase方法之外取消加载,并且我的actionblock不需要取消令牌。我主要停留在等待所有“ProcessCase”排队完成后再继续的部分。Task.WhenAll可能也不适合我的情况,因为任务的数量没有定义,因为它们是由用户手动添加的。@Kurtissaung:我发布的解决方案不需要TPL数据流,也不需要等待所有操作完成,因为只有最新的操作将进入
..//进一步处理
行。