user1968030
user1968030

Reputation:

Using async without await?

Consider Using async without await.

think that maybe you misunderstand what async does. The warning is exactly right: if you mark your method async but don't use await anywhere, then your method won't be asynchronous. If you call it, all the code inside the method will execute synchronously.

I want to write a method that should run async but don't need use await. For example when use a thread

public async Task PushCallAsync(CallNotificationInfo callNotificationInfo)
{
    Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId,
}

I want call PushCallAsync and run async and don't want to use await.

Can I use async without await in C#?

Upvotes: 50

Views: 131229

Answers (5)

ya23
ya23

Reputation: 14526

If Logger.LogInfo is a synchronous method, the whole call will be synchronous anyway. If all you want to do is to execute the code in a separate thread, async is not the tool for the job. Try with thread pool instead:

ThreadPool.QueueUserWorkItem(foo => PushCallAsync(callNotificationInfo));

Upvotes: 3

Kissaki
Kissaki

Reputation: 9237

Given your example

public async Task PushCallAsync(CallNotificationInfo callNotificationInfo)
{
    Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId,
}
  • Logger.LogInfo is called synchronously
  • The async keyword gives the method PushCallAsync the capability to await, but it never awaits anything

If you intend to make the method run asynchronously - as the name PushCallAsync implies -, you have to find an alternative to synchronously calling LogInfo.

If a LogInfoAsync method exists, trying to evade using await is ill-advised. Await is important because:

  • It captures and throws exceptions that may occur on the task execution - which would otherwise be lost / unhandled
  • It ensures execution order by waiting for the result

If you specifically want a fire-and-forget behavior, where you do not depend on execution order (e.g. in this case you don't care about the order of the log messages), you call LogInfoAsync() without awaiting the result.

Since you don't use any await you do not mark the method async. What makes it asynchronous is not the async keyword but it calling other methods asynchronously.

public Task PushCallAsync(CallNotificationInfo callNotificationInfo)
{
    // Fire and forget - we do not care about the result, failure, or order of this log message
    _ = Logger.LogInfoAsync("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId,
    Task.CompletedTask;
}

or non-async

public void PushCall(CallNotificationInfo callNotificationInfo)
{
    // Fire and forget - we do not care about the result, failure, or order of this log message
    _ = Logger.LogInfoAsync("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId,
}

Note that the method name Push implies it is in order. So I would name it differently if you don't care about order. Otherwise, as Push implies, using await would be correct to ensure order.

Upvotes: 3

Visions
Visions

Reputation: 947

If your Logger.LogInfo is already async this is enough:

public void PushCallAsync(CallNotificationInfo callNotificationInfo)
{
    Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId,
}

If it is not just start it async without waiting for it

public void PushCallAsync(CallNotificationInfo callNotificationInfo)
{
    Task.Run(() => Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId));
}

Upvotes: 37

Robetto
Robetto

Reputation: 789

You're misunderstanding async. It actually just tells the Compiler to propagate the inversion of control flow it does in the background for you. So that the whole method stack is marked as async.

What you actually want to do depends on your problem. (Let's consider your call Logger.LogInfo(..) is an async method as it does eventually call File.WriteAsync() or so.

  • If you calling function is a void event handler, you're good. The async call will happen to some degree (namely File.WriteAsync) in the background. You do not expect any result in your control flow. That is fire and forget.
  • If however you want to do anything with the result or if you want to continue only then, when Logger.LogInfo(..) is done, you have to do precautions. This is the case when your method is somehow in the middle of the call-stack. Then Logger.LogInfo(..) will usually return a Task and that you can wait on. But beware of calling task.Wait() because it will dead lock your GUI-Thread. Instead use await or return the Task (then you can omit async):

public void PushCallAsync(CallNotificationInfo callNotificationInfo) 
{
   return Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId); 
}

or

 public async void PushCallAsync(CallNotificationInfo callNotificationInfo) 
 {
    await Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId); 
 }

Upvotes: 6

Stephen Cleary
Stephen Cleary

Reputation: 457147

You still are misunderstanding async. The async keyword does not mean "run on another thread".

To push some code onto another thread, you need to do it explicitly, e.g., Task.Run:

await Task.Run(() => Logger.LogInfo("Pushing new call {0} with {1} id".Fill(callNotificationInfo.CallerId));

I have an async/await intro post that you may find helpful.

Upvotes: 45

Related Questions