在阅读了很多文章以及这个论坛本身之后,我得出了一些结论,我想确认一下。请回答。假设我们的示例async
方法如下所示。请阅读我放置的代码中的注释。假设在这种情况下,getStringTask
和DoIndependentWork()
都需要快速执行,因此整个async
方法AccessTheWebAsync()
将需要快速完成:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com"); //assume it is quick job http request
DoIndependentWork(); //assume it is quick job for loop
string urlContents = await getStringTask;
return urlContents.Length;
}
然后从不同地方拨打电话看起来像:
//example caller from some UI : either Froms or WPF
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
Task<int> getLengthTask = AccessTheWebAsync(); //it' call from UI but but still no need await Task.Run(AccessTheWebAsync) just await cause AccessTheWebAsync takes quick job
SomeIndependentWorkMethodHere;.
int contentLength = await getLengthTask ();
}
//Call from Console application
private async static void Main()
{
Task<int> getLengthTask = AccessTheWebAsync();
SomeIndependentWorkMethodHere;.
int contentLength = await getLengthTask (); //no need Task.Run() at all just await
}
//Call from project library or aspnet controller
private static void MyMethod()
{
Task<int> getLengthTask = AccessTheWebAsync();
SomeIndependentWorkMethodHere;.
int contentLength = await getLengthTask (); //no need Task.Run() at all just await
}
是真的,因为我们的async方法无论在哪里被调用都可以快速完成工作,无论它是从UI / library / console应用程序中调用的,它都只需要使用如下所示的调用方式即可:
await getLengthTask ();
现在让我们考虑相同的情况,但是考虑异步方法中的两个操作都将花费很长时间,或者只是其中之一:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com"); //assume it is long job http request
DoIndependentWork(); //assume it is long job for loop
string urlContents = await getStringTask;
return urlContents.Length;
}
这种情况会改变吗? :
//example caller from some UI : either Froms or WPF
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
SomeIndependentWorkMethodHere;.
await Task.Run(() => AccessTheWebAsync()); // <------ NOW additional Task.Run() is placed
}
//Call from Console application
private async static void Main()
{
Task<int> getLengthTask = AccessTheWebAsync(); // <------- no need to change it's console even if async method is long (just await)
SomeIndependentWorkMethodHere;.
int contentLength = await getLengthTask ();
}
//Call from project library or aspnet controller
private static void MyMethod()
{
Task<int> getLengthTask = AccessTheWebAsync(); // <------- no need to change it's library project (or asp.net controller) even if async method is long (just await)
SomeIndependentWorkMethodHere;.
int contentLength = await getLengthTask ();
}
在这种情况下,与UI
相关的调用Task.Run
已被添加到await
方法中,因为它是UI
并且我们在long running async method
上进行操作。
对于其余console app
和library project
(甚至对于asp.net controller
),签名仍然没有更改。
我的理解正确吗?总结一下,这意味着仅从UI相关的调用中,我需要添加其他Task.Run
,因此,如果await Task.Run(asyncMethod)
方法作为一个整体可能需要很长时间,则async
但仅在时间
否则,等待就足够了。但是对于其余库项目,控制台应用程序,asp.net控制器,总是只使用withotut Task.Run
意味着等待asynMethod(),无论异步方法是否需要快速工作。
答案 0 :(得分:2)
我确信@mjwills已经回答了这个问题。
但是,简单地说。您只有两个问题:
由于您具有CPU和IO混合操作,因此首先要解决的问题。
你在乎吗?好吧...如果这样做,并且您担心会阻塞UI线程或任何其他线程,则唯一明智的选择是在Task
中的 Wrap 中(在某些情况下,情况等待着它)。如果您不在乎,则没有必要。
很少混合使用IO和CPU。但是,是的,我们编写了库和业务层,这确实发生了。如果您所处的环境是个问题,那么除了包装它之外,您将无能为力。
更新
IO通常是由使用IO完成端口,即访问网络或文件系统等的任何东西定义的。
CPU工作负载通常由使用CPU的任何东西,计算,逻辑循环的大定义。确实不是基于IO的任何内容。
更新
每个兔子都可以想到这个问题
全部洗完后,问题问我是否应该在任务中包装一个async
方法,该方法包含阻塞的CPU工作负载,然后等待它。
CPU工作负载会阻塞并且不会放弃线程,除非其假async
,即它已将CPU工作负载内部包装在一个任务中。这不是最佳设计,应该清楚地记录在案。
但是
如果您在服务器环境中,创建新线程/任务并等待它是没有意义的,那么您就不会达到可扩展性点,需要额外的线程,并且调用者仍然必须等待。
如果您处于UI线程中,并且不想使UI停滞,那么,更合适的是启动一个新任务来完成此工作负载并等待它(如果您不想停止消息泵或消息队列,这意味着您不想停止UI)。
如果您在控制台应用程序中,则等待的任务(IO或CPU)将阻止所有问题。你在乎它是否阻塞?如果这样做,则在线程中运行该方法,并将控制权交还控制台,不要等待它,因为这没有任何意义。