Note: This a question for outside of the realm of Asp.Net
and web apps.
In general especially when it comes to libraries or console apps, in order to fire and forget an async method, is it better to just call the async method without await
ing it or use Task.Run
?
Basically:
public static void Main(){
// Doing
_ = DoSomethingAsync();
// vs.
_ = Task.Run(DoSomethingAsync);
}
private static async Task DoSomethingAsync()
{
...
}
In general especially when it comes to libraries or console apps, in order to fire and forget an async method, is it better to just call the async method without awaiting it or use Task.Run?
In general, it's best not to use fire-and-forget at all.
"Fire and forget" means:
In short, "fire and forget" is only appropriate for an extremely small number of tasks. Eg, updating a cache. I'd say probably 85% or more of "fire and forget" code is wrong - it's using fire and forget for code that should not be fire and forget.
So I'd say the best solution is to not use fire and forget at all. At the very least , you should expose a Task
somewhere that represents a "followup action". Consider adding the Task
to your return type or exposing it as a property.
Adopting fire and forget - especially in a library - means you're forcing all consumers to never know when it's safe to shut down and exit. But if you really want to do fire and forget, there are a few options.
A. One option is calling an async void
function without a context . The consuming application still has no way to determine if/when the code completes, but at least that way exceptions are not ignored.
B. Another option is to start the task without a context. This option has both disadvantages of fire and forget code: exceptions are ignored and the calling code cannot know when it completes.
Both of these recommendations start the task without a context. There are helpers for doing this , or you can wrap the call in Task.Run
(slightly less efficient, but it works fine).
I wouldn't recommend starting the task directly. While this would work fine in a Console app, it's not appropriate for libraries which may be called in situations where a context is provided.
In general, it depends but Task.Run
is the safer choice and the reasoning behind it depends on two things:
async
method is always going to be asynchronous. Guaranteeing a method to be always asynchronous can become especially tricky for library projects or if the async method is in a code that is not managed by the caller. For example once I had implemented method similar to this example in a library: public async Task HandleMessages(Func<Task> onMessageNotification)
{
while(true)
{
var msg = MessagingClient.ReceiveMessage();
...
if(msg.MessageType == "MakeAPizza")
{
_ = onMessageNotification();
_ = MakePizzaAsync();
}
}
}
private async Task MakePizzaAsync() {...}
I wanted to fire and forget onMessageNotification
and MakePizzaAsync
since I didn't want it to hold up the message handling. What I didn't catch was when the caller implemented onMessageNotification
like below:
Func<Task> onMsgNotification = () => {
DoSlowOperation();
return Task.CompletedTask;
}
Which would practically made the onMessageNotification
synchronous operation, and had to wait on the DoSlowOperation()
to finish. So in order to avoid to fix issue I just had to change it to:
_ = Task.Run(onMessageNotification);
_ = MakePizzaAsync();
await
operation. The other way that the caller can cause issues is if onMsgnotification
Func were implemented in the following way:Func<Task> onMsgNotification = async () => {
DoSlowOperation();
await AsyncOperation();
}
Which would have still slowed down the HandleMessages
method because DoSlowOperation
is still getting called synchronously.
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.