Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an awaitable method properly

Tags:

c#

async-await

I am writing some awaitable methods and I found a lot of way to do so on the internet. So I came here to know what is really happening on each way, and if some ways must be banished.

As far as I know, there is two kind of awaitable methods:

Those which call other awaitable methods :

public async Task<Foo> GetFooAsync()
{
    var foo = await TrulyGetFooAsync();

    // Do stuff with foo

    return foo;
}

I did not find any other way to do this and I think it is the right way. Tell me if I am wrong !

Those which only call non-awaitable methods :

And here the problems come in my mind.

For example, I saw this:

Exemple 1

public async Task<Foo> GetFooAsync()
{
    return await Task.Run(() => TrulyGetFoo());
}

As far as I understand, the async/await keywords are useless and can be avoided to give this:

Exemple 2

public Task<Foo> GetFooAsync()
{
    return Task.Run(() => TrulyGetFoo());
}

This last example is what I was doing until now. About that, is there a difference between:

Task.Run(() => TrulyGetFoo());

and

Task.Run((Foo)TrulyGetFoo); // I don't know if the cast is required at any time but in my code, it was

???

But I recently found this way:

Exemple 3

public Task<Foo> GetFooAsync()
{
    TaskCompletionSource<Foo> tcs = new TaskCompletionSource<Foo>();
    tcs.SetResult(TrulyGetFoo());
    return tcs.Task;
}

If I understood properly, an awaitable method does not always run on another thread ??? My guess is the third example is providing this mecanism (but how ??? I only see synchronous code in the third example), when the examples 1 and 2 will always run on a worker thread ???

May be there is still another ways to write awaitable methods, so let me know about them.

like image 363
fharreau Avatar asked Sep 03 '25 02:09

fharreau


1 Answers

For example, I saw [Task.Run wrappers around synchronous code]

This is a bad practice. I have a blog post that explains why Task.Run should not be used as a method implementation.

As far as I understand, the async/await keywords are useless and can be avoided

Yes, but I don't recommend eliding async/await in more complex methods.

I recently found [TaskCompletionSource<T>]

As noted in the comments, your code example is still synchronous.

To make it asynchronous, your code should start some operation and return TaskCompletionSource<T>.Task. Then later, whenever that operation completes, your completion handler should call TaskCompletionSource<T>.SetResult (or similar method). For an example, see TAP wrappers for EAP or TAP wrappers for WaitHandles.

TaskFactory.FromAsync is also a wrapper around TaskCompletionSource<T>, and is used for TAP wrappers for APM.

like image 163
Stephen Cleary Avatar answered Sep 04 '25 15:09

Stephen Cleary