总是在库的异步方法中使用 'async' 和 'await' 关键字?
Always use the 'async' and 'await' keywords in asynchronous methods in a library?
总结:在库方法中,我什么时候应该使用 async
和 await
关键字而不是 returning a Task
直接?
我相信我的问题与 this one 有关。但是,这个问题是关于 .NET 4.0
和 TPL,而我使用的是带有 async
和 await
关键字的 .NET 4.6。因此,我认为我的问题可能会得到不同的答案,因为在回答链接问题时这些关键字不存在。
说明: 我正在为外部 WCF 服务编写一个简单的包装器,该包装器进行多次 SendAsync
调用。现在我认为每个包装器方法应该直接 return 一个 Task<>
而不被等待。我的理解是async
/await
应该用在应用层,不是在库里
所以,例如,这是我认为我应该为每个包装器方法采用的方法:
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SendAsync(request);
}
但是在 Internet 上,我发现 几个帖子 改用了这种方法:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SendAsync(request).ConfigureAwait(false);
}
这是我发现的另一个例子 on technet:
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
那么,我什么时候应该使用第二种方法(包含 async
和 await
关键字的方法)?为什么不只 return 整个 Task
而不 PutTaskDelay
async
?我觉得应该尽可能直接returnTask
,只在应用层使用async
/await
得到最终结果。我对吗?如果不是,我在这里展示的两种方法有什么区别?
我的担忧:当使用async
和await
关键字时,似乎它只是为编译器提供了额外的工作而没有任何好处。
不要相信我的话,因为我从来没有那么理解 async/await,但这个想法最让我困扰的是所有使用异步的方法也必须标记为异步,这让我恼火不已。
我想在库中让人们可以选择如何使用这些方法是一件好事,所以你应该使用异步,但我总是发现直接明确使用任务更清楚。
Should I use async await in library?
这一切都取决于。如果您要利用异步编程范例,那么答案是 "yes," async
和 await
关键字是必需的 大多数时候.您很可能会发现自己需要使用 async/await
。这是因为在大多数情况下,仅使用 Task
和 Task<T>
会很困难,因为您很可能需要推断您调用的异步操作的结果。
此外,根据您的问题,您似乎对关键字本身以及它们与 Task
和 Task<T>
类型的关系有些困惑。请允许我为您澄清一下。
async
keyword allows a method to use the await
关键字。最佳做法是让所有异步方法 return Task
或 Task<T>
除非 你不能(例如,按钮单击事件处理程序正如你在上面所展示的那样)。
returnTask
或Task<T>
表示异步操作的方法。当您在图书馆时,建议始终使用 .ConfigureAwait(false)
,原因详述 here. Additionally, I always point people to this detailed article 关于该主题。
要区分您问题中的两种方法:
下面的方法return是Task<SignResponse>
。这是一个异步操作,表示要登录的工作。调用方可以等待该方法以获取 SignResponse
.
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SignAsync(request);
}
同样,这个版本做同样的事情...除了不需要async/await
关键字。不需要它们的原因是方法本身不需要使用 SignResponse
因此它可以简单地 return Task<SignResponse>
如上所示。正如您在问题中指出的那样,当您在不需要 async/await
关键字时使用它们确实会受到惩罚。这样做会在生成结果时添加一个额外的状态机步骤,因为它已等待。
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SignAsync(request).ConfigureAwait(false);
}
最后,如果您需要对响应进行推理,您可以使用上述关键字来这样做:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
var result = await _service.SignAsync(request).ConfigureAwait(false);
if (result.SomeProperty == SomethingWeCareToCheck)
{
_log.Log("Wow, this was un-expected...");
}
return result;
}
总结:在库方法中,我什么时候应该使用 async
和 await
关键字而不是 returning a Task
直接?
我相信我的问题与 this one 有关。但是,这个问题是关于 .NET 4.0
和 TPL,而我使用的是带有 async
和 await
关键字的 .NET 4.6。因此,我认为我的问题可能会得到不同的答案,因为在回答链接问题时这些关键字不存在。
说明: 我正在为外部 WCF 服务编写一个简单的包装器,该包装器进行多次 SendAsync
调用。现在我认为每个包装器方法应该直接 return 一个 Task<>
而不被等待。我的理解是async
/await
应该用在应用层,不是在库里
所以,例如,这是我认为我应该为每个包装器方法采用的方法:
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SendAsync(request);
}
但是在 Internet 上,我发现 几个帖子 改用了这种方法:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SendAsync(request).ConfigureAwait(false);
}
这是我发现的另一个例子 on technet:
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
那么,我什么时候应该使用第二种方法(包含 async
和 await
关键字的方法)?为什么不只 return 整个 Task
而不 PutTaskDelay
async
?我觉得应该尽可能直接returnTask
,只在应用层使用async
/await
得到最终结果。我对吗?如果不是,我在这里展示的两种方法有什么区别?
我的担忧:当使用async
和await
关键字时,似乎它只是为编译器提供了额外的工作而没有任何好处。
不要相信我的话,因为我从来没有那么理解 async/await,但这个想法最让我困扰的是所有使用异步的方法也必须标记为异步,这让我恼火不已。
我想在库中让人们可以选择如何使用这些方法是一件好事,所以你应该使用异步,但我总是发现直接明确使用任务更清楚。
Should I use async await in library?
这一切都取决于。如果您要利用异步编程范例,那么答案是 "yes," async
和 await
关键字是必需的 大多数时候.您很可能会发现自己需要使用 async/await
。这是因为在大多数情况下,仅使用 Task
和 Task<T>
会很困难,因为您很可能需要推断您调用的异步操作的结果。
此外,根据您的问题,您似乎对关键字本身以及它们与 Task
和 Task<T>
类型的关系有些困惑。请允许我为您澄清一下。
async
keyword allows a method to use the await
关键字。最佳做法是让所有异步方法 return Task
或 Task<T>
除非 你不能(例如,按钮单击事件处理程序正如你在上面所展示的那样)。
returnTask
或Task<T>
表示异步操作的方法。当您在图书馆时,建议始终使用 .ConfigureAwait(false)
,原因详述 here. Additionally, I always point people to this detailed article 关于该主题。
要区分您问题中的两种方法:
下面的方法return是Task<SignResponse>
。这是一个异步操作,表示要登录的工作。调用方可以等待该方法以获取 SignResponse
.
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SignAsync(request);
}
同样,这个版本做同样的事情...除了不需要async/await
关键字。不需要它们的原因是方法本身不需要使用 SignResponse
因此它可以简单地 return Task<SignResponse>
如上所示。正如您在问题中指出的那样,当您在不需要 async/await
关键字时使用它们确实会受到惩罚。这样做会在生成结果时添加一个额外的状态机步骤,因为它已等待。
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SignAsync(request).ConfigureAwait(false);
}
最后,如果您需要对响应进行推理,您可以使用上述关键字来这样做:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
var result = await _service.SignAsync(request).ConfigureAwait(false);
if (result.SomeProperty == SomethingWeCareToCheck)
{
_log.Log("Wow, this was un-expected...");
}
return result;
}