I'm building a .NET 4.0 application that uses ADO.NET, so I cannot use async/await. I don't want a solution for that, but I do want to know what of the following implementations is best and why. My unit tests pass for all three implementations, but I want to know the difference between these three.
In my first implementation I wrap a task in another task. I think spinning up two tasks is bad for performance, but I'm not sure.
public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
var sqlCommand = CheckIfSqlCommand(dbCommand);
PrepareExecuteReader(dbCommand);
return Task<IDataReader>
.Factory
.FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null)
.Result;
}, cancellationToken);
}
Then I tried wrapping the result in a TaskCompletionSource
so I just have one task.
public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
var taskCompletionSource = new TaskCompletionSource<IDataReader>();
var sqlCommand = CheckIfSqlCommand(dbCommand);
PrepareExecuteReader(dbCommand);
var reader = Task<IDataReader>
.Factory
.FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null)
.Result;
taskCompletionSource.SetResult(reader);
return taskCompletionSource.Task;
}
My final solution is to directly return the task I created instead of wrapping it.
public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
var sqlCommand = CheckIfSqlCommand(dbCommand);
PrepareExecuteReader(dbCommand);
return Task<IDataReader>
.Factory
.FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null);
}
What option should I use or is there a better way to do this?
Your #3 is the best. The first two introduce complication for no reason.
1 potentially adds another thread purely to run CheckIfSqlCommand()
and PrepareExecuteReader()
asynchronously. This may be what you wanted, but they don't sound like commands that are going to take a long time.
2 references .Result
of the task, which will block until the task is complete, so defeats the whole purpose of using tasks.
There are two scenes we use asynchronous programming with Tasks
, one is massive computing, another is I/O
.
In massive computing situation, we always use Task.Run
to ask a thread from thread pool to avoid blocking thread.
In I/O
situation, if async
api is not provided, we always use TaskCompletionSource
or Task.Factory.FromAsync
to build an async
method. I think mix these two is not a good solution.
By the way, Task.Run
is always been used in client application, server end generally not used Task.Run
due to concurrent request.
Here is a good post you can refer to:
https://docs.microsoft.com/en-us/archive/msdn-magazine/2010/september/async-tasks-simplify-asynchronous-programming-with-tasks
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.