Summary: In a library method, when should I use the async
and await
keywords instead of returning a Task
directly?
I believe my question is related to this one. However, that question is about .NET 4.0
and the TPL, while I'm using .NET 4.6 with the async
and await
keywords. So, I think my question might get different answers because these keywords didn't exist when the linked question was answered.
Explanation: I'm writing a simple wrapper for an external WCF service and the wrapper makes multiple SendAsync
calls. Now I think that each wrapper method should just return a Task<>
directly without being awaited. My understanding is that async
/await
should be used on the application layer, and not within a library.
So, for example, here is the approach that I think I should take for each wrapper method:
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SendAsync(request);
}
But on the Internet, I found several posts that use this approach instead:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SendAsync(request).ConfigureAwait(false);
}
And here is another example that I found on technet:
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
So, when should I use the second approach (the one that includes the async
and await
keywords)? Why not just return a whole Task
without making PutTaskDelay
async
? I think that I should return Task
directly whenever it is possible, and use async
/await
to get a final result in the application layer only. Am I right? If not, what is the difference between the two approaches that I show here?
My concern: When the async
and await
keywords are used, it seems that it just provides additional work to the compiler without any benefit.
Should I use async await in library?
It all depends. If you're going to take advantage of the asynchronous programming paradigm, then the answer is "yes," the async
and await
keywords are needed most of the time. More than likely, you will find yourself needing to use async/await
. That is because in most situations it would be difficult to use only Task
and Task<T>
as you will more than likely need to reason about the results of the async operations that you invoke.
Additionally, based on your question it seems as though you may have some confusion about the keywords themselves and how they relate to the Task
and Task<T>
types. Allow me to clarify this for you.
The async
keyword allows a method to use the await
keyword. The best practice is to have all async methods return either Task
or Task<T>
unless you are unable to (for example, a button click event handler as you demonstrated above).
Methods that return Task
or Task<T>
represent asynchronous operations. When you are in a library it is suggested to always use .ConfigureAwait(false)
for reasons detailed here. Additionally, I always point people to this detailed article on the subject.
To differentiate the two approaches in your question:
The method below returns a Task<SignResponse>
. This is an async operation that represents the work to sign in. The method can be awaited by the caller to get SignResponse
.
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SignAsync(request);
}
Likewise, this version does the same thing...except that the async/await
keywords are not needed. The reason they are not needed is that the method itself does not need to use SignResponse
and therefore it could simply return Task<SignResponse>
as shown above. And as you indicated in your question, there is indeed a penalty when you use the async/await
keywords when they are not needed. Doing so adds an extra state machine step as the result is yielded, since its awaited.
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SignAsync(request).ConfigureAwait(false);
}
Finally, if you needed to reason about the response, you could use the aforementioned keywords to do so like this:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
var result = await _service.SignAsync(request).ConfigureAwait(false);
if (result.SomeProperty == SomethingWeCareToCheck)
{
_log.Log("Wow, this was un-expected...");
}
return result;
}
Don't take my word for it, because I never understood async/await that well, but what bothered me most about the idea was that all methods using async had to be marked as async as well, which annoyed me to no end.
I guess in a library giving people the option to choose how to use the methods is a good thing, so you should use async, however I always found it more clear to explicitly use the Tasks directly.
来源:https://stackoverflow.com/questions/35987375/always-use-the-async-and-await-keywords-in-asynchronous-methods-in-a-library