Трябва ли да обвия задача в друга задача или просто да върна създадената задача?

Създавам приложение .NET 4.0, което използва ADO.NET, така че не мога да използвам async/await. Не искам решение за това, но искам да знам коя от следните реализации е най-добра и защо. Моите модулни тестове преминават и за трите реализации, но искам да знам разликата между тези три.

#1 Задачи за влагане

При първото си изпълнение обгръщам задача в друга задача. Мисля, че завъртането на две задачи е лошо за производителността, но не съм сигурен.

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 Използване на TaskCompletionSource

След това се опитах да опаковам резултата в TaskCompletionSource, така че имам само една задача.

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 връщане на Задача директно

Последното ми решение е директно да върна задачата, която създадох, вместо да я обвивам.

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

Така че основно въпросът ми е:

Каква опция да използвам или има ли по-добър начин да направя това?


person annemartijn    schedule 27.02.2014    source източник
comment
Насочването към .Net 4.0 не означава непременно, че не можете да използвате async-await. Можете да го използвате, ако добавите Microsoft.Bcl.Async към вашия проект, въпреки че изисква VS 2012.   -  person svick    schedule 27.02.2014
comment
Разработчиците също трябва да могат да използват vs2010, но оценявам отзивите ви.   -  person annemartijn    schedule 28.02.2014


Отговори (2)


Вашият номер 3 е най-добрият. Първите две внасят усложнения без причина.

1 потенциално добавя друга нишка само за изпълнение на CheckIfSqlCommand() и PrepareExecuteReader() асинхронно. Това може да е това, което сте искали, но те не звучат като команди, които ще отнемат много време.

2 препратки .Result на задачата, които ще блокират, докато задачата не бъде завършена, така че отменя цялата цел на използването на задачи.

person GazTheDestroyer    schedule 27.02.2014
comment
Чудя се дали има ситуации, в които не използвате задачи за I/O или работа в мрежа. Ако има, как да разбера кога да използвам асинхронност? - person annemartijn; 27.02.2014
comment
@annemartijn, ако трябва да питате, не използвайте async. Използвайте го, когато трябва. - person usr; 27.02.2014

Има две сцени, които използваме асинхронно програмиране с Tasks, едната е масивно изчисление, другата е I/O.
В ситуация на масивно изчисление винаги използваме Task.Run, за да поискаме нишка от пула от нишки, за да избегнем блокиране на нишка.
В I/O ситуация, ако async api не е предоставен, ние винаги използваме TaskCompletionSource или Task.Factory.FromAsync за изграждане на async метод. Мисля, че смесването на тези две не е добро решение.
Между другото, Task.Run винаги се използва в клиентско приложение, краят на сървъра обикновено не се използва Task.Run поради едновременна заявка.
Ето една добра публикация, която можете вижте:
https://docs.microsoft.com/en-us/archive/msdn-magazine/2010/september/async-tasks-simplify-asynchronous-programming-with-tasks

person 西红柿炒恐龙蛋    schedule 04.03.2021