我在过去2天内一直在阅读有关c#异步方法的内容,据我所知,与线程(threadpool.queueuserworkitem())
不同,对异步方法的调用不会立即返回,只会在调用方法时返回等待或完成(或例外)
请参阅以下示例。
public partial class MainWindow : Window
{
// . . .
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// ONE
Task<int> getLengthTask = AccessTheWebAsync();
// FOUR
int contentLength = await getLengthTask;
// SIX
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
// TWO
HttpClient client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("http://msdn.microsoft.com");
// THREE
string urlContents = await getStringTask;
// FIVE
return urlContents.Length;
}
}
从我收集的内容中,在上面的代码中,AccessTheWebAsync()
被同步调用(即,在调用时,控制不会立即返回)。但是在名为“THREE”的行中,运行时将返回控制权。
我的问题是:
运行时如何决定何时使用线程池或何时在调用线程中运行任务? (即执行代码而不返回控制权)
上面代码中的哪些点会使用新线程(或线程池)?
如果AccessTheWebAsync()
执行计算密集型操作,例如运行具有无数次迭代的循环,则控件将仅在循环完成时返回到调用者。是吗?
在异步函数中,有没有办法立即返回控件然后继续在后台线程中执行工作? (就像我们调用了threadpool.queueuserworkitem())
调用异步方法而没有await(假设可能)与调用非异步方法相同吗?
答案 0 :(得分:5)
首先重要的是:如果要等待的任务尚未完成,运行时将只返回await
上的调用者。
问题1:我将在这里引用MSDN:
async和await关键字不会导致创建其他线程。异步方法不需要多线程,因为异步方法不能在自己的线程上运行。
问题2:可能在GetStringAsync
的实施中,但我们不知道,我们也不必知道它。这足以让我们知道GetStringAsync
以某种方式得到它的结果而不会阻塞我们的线程。
问题3:如果循环放在await
关键字之前,是的。
问题4:引用与之前相同的段落:
您可以使用Task.Run将CPU绑定的工作移动到后台线程
您不需要async
和await
个关键字。例如:
private Task<int> DoSomethingAsync()
{
return Task.Run(() =>
{
// Do CPU heavy calculation here. It will be executed in the thread pool.
return 1 + 1;
});
}
问题5:我会再次引用
异步方法通常包含一个或多个await运算符,但缺少await表达式不会导致编译器错误。如果异步方法不使用await运算符来标记挂起点,则该方法将作为同步方法执行,尽管存在异步修饰符。编译器会发出此类方法的警告。
Source(与之前相同的页面,只是一个不同的部分)
答案 1 :(得分:3)
运行时如何决定何时使用线程池或何时在调用线程中运行任务?
如果存在同步上下文并且您没有明确指定您不想继续上下文(通过使用await task.ConfigureAwait(false)
之类的内容),则该方法将在捕获的上下文上继续。在UI应用程序中,该上下文是UI线程,假设从UI线程调用该方法。
上面代码中的哪些点,将使用新线程(或线程池)?
无处。除非您另行指定(参见上文),否则await
将恢复捕获的上下文,在您的情况下是UI线程。
如果
AccessTheWebAsync()
执行计算密集型操作,例如运行具有无数次迭代的循环,则控件将仅在循环完成时返回到调用者。是吗?
是的,假设循环在第一个“异步”await
之前。 (await
ed await
已完成后,{Task
也可以是“同步”。)
在异步函数中,有没有办法立即返回控件,然后继续以后台线程的形式进行工作?
您应该使用Task.Run()
。
在没有await的情况下调用异步方法(假设它可能)与调用非异步方法相同吗?
有可能,编译器会警告您该方法将完全同步执行。