Should I wrap a task in another task or should I just return the created task?

穿精又带淫゛_ 提交于 2020-01-14 09:49:06

问题


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.

#1 Nesting tasks

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);
}

#2 Using TaskCompletionSource

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;
}

#3 returning Task directly

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);
}

So basically my question is:

What option should I use or is there a better way to do this?


回答1:


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.



来源:https://stackoverflow.com/questions/22063721/should-i-wrap-a-task-in-another-task-or-should-i-just-return-the-created-task

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!