简体   繁体   中英

Any way to wait for all tasks to be complete in ActionBlock?

First of all, let me describe the flow of the program I am writing.

There is a list of objects in the GUI and when the user clicks on one, the object data is read from the disk and is loaded. This could take around 3-4 seconds.

Let's say the user is impatient and clicks on another object while the first one is still loading. The program will load the second object and at the same time, will cancel the loading for the first object.

As the user could spam load operations before any of them could complete successfully, I have implemented an action block to queue up all the load operations.

So I have an action block like this:

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

Every time the user has clicked on a Case Object, I will call:

this.loadObjectActionBlock.Post(CaseObject);

And the CaseObject will be processed by a function I have defined like this:

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

What I need to do right now is, I need to wait until ALL CaseObjects are loaded so that I could continue my code after that.

I have tried detecting when all cases are processed by calling

if (this.loadObjectActionBlock.InputCount == 0)
{
    this.loadObjectActionBlock.Complete();
}

after caseObject.LoadCaseData(); but this leads to strange results when load actions happen way too fast and the action block is told not to accept any more inputs. If I understand correctly, the InputCount property only looks at the number of jobs left in the queue.

So what I'd like to do is I'd like to await the ActionBlock like:

await this.loadObjectActionBlock.Completion;

when everything in the queue has been fully processed.

I may not be using the ActionBlock as it is intended to, so if there are any alternatives on this, please kindly suggest anything that I could read up on.

TLDR: I'd like to process multiple tasks (started by user) concurrently and wait for all to be complete then followed by a single task.

Thanks in advance :)

The program will load the second object and at the same time, will cancel the loading for the first object.

A queue is not the appropriate solution for this behavior, especially since a TPL block can only be completed once.

If you want to implement this behavior, simply ensure the cancellation token is observed before continuing with the next operation:

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

Called from the UI thread as:

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));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM