How better to create async wrapper for synchronous method?
// sync method
public void LongOperation()
{
//code...
}
// versions of wrapper
public async Task LongOpertionWrapperAsyncV1()
{
var task = Task.Factory.StartNew(LongOperation);
await task.ConfigureAwait(false);
}
public Task LongOpertionWrapperAsyncV2()
{
var task = Task.Factory.StartNew(LongOperation);
task.ConfigureAwait(false);
return task;
}
Although the use of both versions don't differ.
async Task Executor()
{
await LongOpertionWrapperAsyncV1();
await LongOpertionWrapperAsyncV2();
}
For methods that return value (Task<T>), I use the first version.
But I would like to know your opinion.
And there is a general difference between these versions?
Neither solution is correct. The best answer is to not expose asynchronous methods for synchronous code. I go more into the "why" on my blog.
If your code is asynchronous, then use async
and await
. If it's not, then don't. It should be up to the caller how they want to invoke the code (e.g., using Task.Run
).
You should use "something like" V2:
public Task LongOpertionWrapperAsyncV2()
{
return Task.Run(LongOperation);
}
and
async Task Executor()
{
await LongOpertionWrapperAsyncV2().ConfigureAwait(false);
}
This saves you one context-switch compared to V1. As long as you do not need to "await another operation" and the async-Task is the last operation in the method you can just return the task instead of awaiting it and leave the await to the caller (which also can or can not add ConfigureAwait
).
Task.Factory.StartNew
is only necessary if you want to supply TaskCreationOptions.LongRunning
like HPT suggested.
UPDATE:
As Stephen already meantioned: There are VERY few cases where you should do async over sync
(but there are). So think about what exectly you are doing before implementing something like this. Simplified said: If it is CPU-bound work DON'T do it, if it is some kind of "waiting for IO" MAYBE do it.
We have a case here where we developed a "nearly async all the way" library, which is to control different HW-devices. There the whole "generic library" is asynchronous, but some of the low-level device drivers and/or access libraries do not support async
so on the very lowest level we do something like:
public Task<byte[]> ReadAsync(int length)
{
return Task.Run(() => hwDevice.Read(length));
}
The hwDevice.Read
does still lock the thread, but not the CPU, so the UI is responsive during that time we are waiting for the IO (in "real live" the is also some cancellation and error handling logic around it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With