我正在尝试熟悉c#的新await / async关键字,我发现了几个我无法理解的方面。
让我们从竞争条件开始:
Stream s=...
...
for(int i=0;i<100;i++)
{
s.WriteAsync(new byte[]{i},0,1);
}
这会一直按预期工作(例如写入文件12345 .....而不是13254或其他东西)?
第二件事是异步函数如果不包含await运算符则同步执行。而且,根据microsoft文档,异步函数总是在调用者线程中执行(与BeginInvoke相比)。这让我想到了3个下一个问题:
异步函数在释放给调用函数之前执行多少次?
async void MyAsyncFunction()
{
Operation1();
Operation2();
Operation3();
....
Stream s=...;
await s.WriteAsync(....);
}
在我读过的关于await / async的文章中,有人说没有await运算符的异步函数按顺序执行,并且async / await立即返回。但是我在唠叨MyAsyncFunction
可能总是执行Operation1 ... Operation3,然后在await s.WriteAsync
点击时发布。
如果我在异步函数中使用Thread.Sleep
,如下所示:
async void DoStuff()
{
Stream s=...;
...
await s.WriteAsync(....);
Thread.Sleep(10000);
....
}
Thread.Sleep会阻塞执行它的整个线程还是阻止异步函数?
如果我在其中一个异步函数中使用semaphore.Wait()
,并且希望信号量由其他异步函数释放,该怎么办?这会像线程那样运行,还是会导致死锁?
await
在异步函数之外无效。为什么呢?
答案 0 :(得分:16)
我建议您阅读我的async
intro。
这会一直按预期工作(例如写入文件12345 .....而不是13254或其他东西)?
没有。您需要await
对WriteAsync
的调用。
异步函数在释放给调用函数之前执行了多少?
直到它await
一个尚未完成的操作。
Thread.Sleep会阻塞执行它的整个线程还是阻止异步函数?
Thread.Sleep
- 以及所有其他阻塞方法 - 将阻止async
方法和正在执行它的线程。
作为一般规则,请勿在{{1}}方法中使用任何阻止方法。
如果我在其中一个异步函数中使用semaphore.Wait(),并且它希望信号量由其他异步函数释放,该怎么办?这会像线程一样运行,还是会导致死锁?
这完全取决于你的背景。 async
是一种阻止方法,因此如果“其他”Wait
方法需要被阻止方法保存的上下文,那么您将陷入僵局。
请注意async
为SemaphoreSlim
- 友好;您可以使用async
代替WaitAsync
。
await在异步函数之外不起作用。为什么呢?
因为Wait
关键字启用了async
关键字。这样做是为了最大限度地减少新关键字对C#语言和代码可读性的影响。
答案 1 :(得分:15)
您可以在以下post by Eric Lippert中找到有关await
运算符的问题的答案,其中他说:
“await”运算符......并不意味着“此方法现在阻止了 当前线程,直到异步操作返回“。那会 将异步操作恢复为同步 操作,这正是我们试图避免的。相反, 它意味着与此相反;它意味着“如果我们正在等待任务 还没有完成,然后注册这个方法的其余部分 继续该任务,然后立即返回给您的呼叫者; 任务将在完成时调用continuation。 - Eric Lippert
答案 2 :(得分:0)
简而言之,似乎答案是&#34;非常&#34;。虽然以下内容可能无法回答您的所有问题,但我认为它适用于一般情况下的用例。想想你的Stream而不是他们所指的网络IO。
在重叠网络IO的情况下,将使用IO完成端口,回调由硬件中断触发。
这意味着我们等待着#34;完成后,线程不会被消耗掉。 [...]
可以在1个线程上执行所有操作。 [...]然而,它将取决于平台,&#34; awaiter&#34;实施&amp;正在使用的同步上下文。
http://social.msdn.microsoft.com/Forums/en-US/async/thread/a46c8a54-f8d4-4fa9-8746-64d6a3a7540d/