Разница между Task.Factory.FromAsync и BeginX / EndX? - PullRequest
11 голосов
/ 28 сентября 2011

У меня очень похожий код при использовании стандартных методов BeginRead и EndRead из TcpClient и использовании Task.Factory.FromAsync.

Вот несколько примеров. Код обработки ошибок не показан.

Task.Factory.FromAsync:

private void Read(State state)
{
    Task<int> read = Task<int>.Factory.FromAsync(state.Stream.BeginRead, state.Stream.EndRead, state.Bytes, state.BytesRead, state.Bytes.Length - state.BytesRead, state, TaskCreationOptions.AttachedToParent);

    read.ContinueWith(FinishRead);
}

private void FinishRead(Task<int> read)
{
    State state = (State)read.AsyncState;

    state.BytesRead += read.Result;
}

Стандартное использование обратных вызовов с BeginRead и EndRead:

private void Read(State state)
{
    client.BeginRead(state.Bytes, state.BytesRead, state.Bytes.Length - state.Bytes.Read, FinishRead, state);
}

private void FinishRead(IAsyncResult async)
{
    State state = (State)async.AsyncState;

    state.BytesRead += state.Stream.EndRead(async);
}

Обе эти работыхорошо, но мне любопытно их различия.Строки кода для обоих в значительной степени эквивалентны, и они, кажется, выполняют точно такую ​​же функцию и имеют одинаковую эффективность.Какой из них предпочтительнее?Что бы вы предпочли увидеть в рабочем коде?

1 Ответ

14 голосов
/ 28 сентября 2011

Я бы предпочел увидеть код Task<T>:

  • Это обеспечивает состав более легко; например, достаточно просто написать метод, который принимает набор задач Task<T> и возвращает другую задачу, которая представляет вердикт большинства этих задач. Точно так же вы можете подождать, пока не будет выполнено одно из заданий и т. Д.
  • Обеспечивает более гибкое планирование запуска продолжения.
  • Позволяет возвращать само задание с безопасностью типов и гораздо большей информацией, чем несколько анемичный тип IAsyncResult, возвращаемый BeginRead.
  • Проще указать обработку ошибок и отмену с задачами, чем использовать модель Begin / End.
  • Task<T> получает лучшую языковую поддержку в C # 5 с помощью async / await - если ваша кодовая база уже использует Task<T> повсеместно, будет намного проще воспользоваться этим

По сути, в современном коде, работающем в .NET 4, Task<T> - идиоматический способ представления текущей задачи. Это намного более богатая среда для работы, чем предыдущие попытки, и я бы принял ее, если бы у вас была такая возможность. Очевидно, что если вы используете .NET 3.5 или более раннюю версию, жизнь становится немного сложнее, но я предполагаю, что когда вы задаете вопрос, Task<T> - это вариант ...

...