Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom awaitables for dummies

In Async/Await FAQ, Stephen Toub says:

An awaitable is any type that exposes a GetAwaiter method which returns a valid awaiter.
...
An awaiter is any type returned from an awaitable’s GetAwaiter method and that conforms to a particular pattern.

So in order to be an awaiter, a type should:

  • Implement the INotifyCompletion interface.
  • Provide a boolean property called IsCompleted.
  • Provide a parameterless GetResult method that returns void or TResult.

(I'm ignoring ICriticalNotifyCompletion for now.)

I know the page I mentioned has a sample that shows how the compiler translates await operations but I'm stil having a hard time understanding.

When I await an awaitable,

  • When is IsCompleted checked? Where should I set it?
  • When is OnCompleted called?
  • Which thread calls OnCompleted?
  • I saw examples of both directly invoking the continuation parameter of OnCompleted and using Task.Run(continuation) in different examples, which should I go for and why?
like image 315
Şafak Gür Avatar asked Sep 30 '12 12:09

Şafak Gür


2 Answers

Why would you want a custom awaiter?

You can see the compiler's interpretation of await here. Essentially:

var temp = e.GetAwaiter();
if (!temp.IsCompleted)
{
  SAVE_STATE()
  temp.OnCompleted(&cont);
  return;

cont:
  RESTORE_STATE()
}
var i = temp.GetResult();

Edit from comments: OnCompleted should schedule its argument as a continuation of the asynchronous operation.

like image 138
Stephen Cleary Avatar answered Nov 09 '22 22:11

Stephen Cleary


In the vast majority of cases, you as a developer need not worry about this. Use the async and await keywords and the compiler and runtime handle all this for you.

To answer your questions:

When does the code checks IsCompleted? Where should I set it?

The task should set IsCompleted when the task has finished doing what it was doing. For example, if the task was loading data from a file, IsCompleted should return true when the data is loaded and the caller can access it.

When does it calls OnCompleted?

OnCompleted usually contains a delegate supplied by the caller to execute when the task has completed.

Does it call OnCompleted in parallel or should the code inside OnCompleted be asynchronous?

The code in OnCompleted should be thread neutral (not care which thread it is called from). This may be problematic for updating COM objects in Single Threaded Apartments (like any UI classes in Metro/Windows8/Windows Store apps). It does not have to be asynchronous but may contain asynchronous code.

I saw examples of both directly invoking the continuation parameter of OnCompleted and using Task.Run(continuation) in different examples, which should I go for and when?

Use async/await when you can. Otherwise, use Task.Run() or Task.Wait() because they follow the sequential programming model most people are used to. Using continuations may still be required, particularly in Metro apps where you have apartment issues.

like image 44
akton Avatar answered Nov 09 '22 21:11

akton