问题 Task.Factory.FromAsync和BeginX / EndX之间的区别?


当使用TcpClient中的标准BeginRead和EndRead方法并使用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);
}

这两个都很好,但我很好奇他们的差异。两者的代码行几乎相同,它们似乎都执行完全相同的功能并具有相同的效率。哪个更好?您更愿意在生产代码中看到什么?


3436
2017-09-28 06:06


起源



答案:


我宁愿看 Task<T> 基础代码:

  • 它更容易提供构图;例如,编写一个收集的方法相当容易 Task<T> 任务并返回另一个代表这些任务的多数裁决的任务。同样,您可以等到任务集合中的任何一个完成,等等。
  • 它提供了更灵活的连续运行位置安排。
  • 它允许任务本身返回类型安全和比有点贫血更多的信息 IAsyncResult 返回的类型 BeginRead
  • 使用任务指定错误处理和取消比使用Begin / End模型更简单。
  • Task<T> 如果您的代码库已经使用,那么使用async / await在C#5中获得更好的语言支持 Task<T> 普遍地,它将是 许多 更容易利用这一点

基本上在.NET 4上运行的现代代码中, Task<T> 是表示正在进行的任务的惯用方式。与早期的尝试相比,这是一个更富裕的工作环境,如果你有机会,我会接受它。显然,如果你使用的是.NET 3.5或更早版本,那么生活会有点困难,但我假设你在问这个问题, Task<T> 是一个选择......


14
2017-09-28 06:13



谢谢回复!我仍然有点困惑。我知道BeginRead非常有效,因为回调使用IO完成端口而不是阻塞。 Contine在效率方面是否相同,因为它不会阻塞并且只在EndRead运行的同时运行?另外,您能详细说明它如何支持更好的错误处理吗?我不是也必须在两者上做同样的试试 state.BytesRead +=  每个代码示例中的行? - Ryan Peschel
@RyanPeschel:是的,它不会阻止 - 否则它将毫无意义。不,你不需要相同的try / catch,因为你可以指定一个延迟来运行错误,另一个继续运行取消,另一个运行成功 - 查看ContinueWith的重载。你也可以 测试 一个任务的状态,而不只是试图得到结果(看看Task.Status)。基本上,整个事情要丰富得多。 C#5中的异步支持非常棒。 - Jon Skeet
我正在查看超载情况,但我不太了解你的情况。如何在出现错误/取消时指定运行方法? - Ryan Peschel
我想我可能已经找到了..你会用不同的函数多次调用ContinueWith,第二个参数就是这样的 TaskContinuationOptions.OnlyOnFaulted 如果你想要所说的方法运行,如果有错误? - Ryan Peschel
@RyanPeschel:我在这里不能详细说明,因为我正在打电话,但请看TaskContinuationOptions。编辑:刚看到你的编辑;是的,这就是我所说的。请注意,您可以附加多个延续。 - Jon Skeet


答案:


我宁愿看 Task<T> 基础代码:

  • 它更容易提供构图;例如,编写一个收集的方法相当容易 Task<T> 任务并返回另一个代表这些任务的多数裁决的任务。同样,您可以等到任务集合中的任何一个完成,等等。
  • 它提供了更灵活的连续运行位置安排。
  • 它允许任务本身返回类型安全和比有点贫血更多的信息 IAsyncResult 返回的类型 BeginRead
  • 使用任务指定错误处理和取消比使用Begin / End模型更简单。
  • Task<T> 如果您的代码库已经使用,那么使用async / await在C#5中获得更好的语言支持 Task<T> 普遍地,它将是 许多 更容易利用这一点

基本上在.NET 4上运行的现代代码中, Task<T> 是表示正在进行的任务的惯用方式。与早期的尝试相比,这是一个更富裕的工作环境,如果你有机会,我会接受它。显然,如果你使用的是.NET 3.5或更早版本,那么生活会有点困难,但我假设你在问这个问题, Task<T> 是一个选择......


14
2017-09-28 06:13



谢谢回复!我仍然有点困惑。我知道BeginRead非常有效,因为回调使用IO完成端口而不是阻塞。 Contine在效率方面是否相同,因为它不会阻塞并且只在EndRead运行的同时运行?另外,您能详细说明它如何支持更好的错误处理吗?我不是也必须在两者上做同样的试试 state.BytesRead +=  每个代码示例中的行? - Ryan Peschel
@RyanPeschel:是的,它不会阻止 - 否则它将毫无意义。不,你不需要相同的try / catch,因为你可以指定一个延迟来运行错误,另一个继续运行取消,另一个运行成功 - 查看ContinueWith的重载。你也可以 测试 一个任务的状态,而不只是试图得到结果(看看Task.Status)。基本上,整个事情要丰富得多。 C#5中的异步支持非常棒。 - Jon Skeet
我正在查看超载情况,但我不太了解你的情况。如何在出现错误/取消时指定运行方法? - Ryan Peschel
我想我可能已经找到了..你会用不同的函数多次调用ContinueWith,第二个参数就是这样的 TaskContinuationOptions.OnlyOnFaulted 如果你想要所说的方法运行,如果有错误? - Ryan Peschel
@RyanPeschel:我在这里不能详细说明,因为我正在打电话,但请看TaskContinuationOptions。编辑:刚看到你的编辑;是的,这就是我所说的。请注意,您可以附加多个延续。 - Jon Skeet