Best Practice for ITargetBlock <TInput> .Completion.ContinueWith ()

This question is about best practices when using ContinueWith() to handle the completion of a TPL data block.

The ITargetBlock<TInput>.Completion() method allows asynchronously processing completion of the database creation using ContinueWith() .

Consider the following Console application code, which demonstrates very simple use:

 private static void Main() { test().Wait(); } static async Task test() { var transform = new TransformBlock<int, double>(i => i/2.0); var output = new ActionBlock<double>(d => Console.WriteLine(d)); // Warning CS4014 here: transform.Completion.ContinueWith(continuation => output.Complete()); transform.LinkTo(output); for (int i = 0; i < 10; ++i) await transform.SendAsync(i); transform.Complete(); await output.Completion; } 

The code has a very simple TransformBlock , which divides integers by 2.0 and turns them into doubles. The converted data is processed using ActionBlock , which simply displays the values ​​in the console window.

Conclusion:

 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 

When the TransformBlock complete, I want to populate the ActionBlock as well. It is convenient to do so:

 transform.Completion.ContinueWith(continuation => output.Complete()); 

And here is the problem. Since this is inside the async method, and I ignore the return value from ContinueWith() , I get a compiler warning:

warning CS4014: because this call is not expected, execution of the current method continues until the call is completed. Consider applying the wait statement to a call result.

It is clear that I cannot await call, as warned by a warning - if I do, the code freezes because the CompleteWith() task cannot be completed until transform.Complete() is called.

Now I have no problem handling the warning itself (I can simply suppress it or assign the task to a variable or use the extension of the task .Forget() , etc.) - but here are my questions:

  • Is it safe to handle the associated completion of a DataBlock this way?
  • Is there a better way?
  • Is there anything important here that I missed?

I think that if I continued to do anything other than output.Complete() inside the continuation, I would have to provide exception handling - but maybe even just calling output.Complete() fraught with danger?

+5
source share
1 answer

While you can implement distribution distribution yourself, TPL Dataflow does this for you with DataflowLinkOptions.PropagateCompletion :

 transform.LinkTo(output, new DataflowLinkOptions {PropagateCompletion = true}); 

If you still want to implement this yourself, you can solve the problem to save the task and waiting for it when using Task.WhenAll :

 static async Task test() { var transform = new TransformBlock<int, double>(i => i/2.0); var output = new ActionBlock<double>(d => Console.WriteLine(d)); // Warning CS4014 here: var continuation = transform.Completion.ContinueWith(_ => output.Complete()); transform.LinkTo(output); for (int i = 0; i < 10; ++i) await transform.SendAsync(i); transform.Complete(); await Task.WhenAll(continuation, output.Completion) } 

This allows you to handle any exceptions in output.Complete and remove the warning.

+7
source

Source: https://habr.com/ru/post/1208669/


All Articles