线程的等待/异步有多么不同?

Ars*_*ray 23 .net c# multithreading async-await

我正在尝试熟悉c#的新await/async关键字,我发现了几个我无法理解的方面.

  1. 让我们从竞争条件开始:

    Stream s=...
    ...
    for(int i=0;i<100;i++)
    {
        s.WriteAsync(new byte[]{i},0,1);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这将按预期一直工作(例如写入文件12345 .....而不是13254或其他东西)?

    第二件事是异步函数如果不包含await运算符则同步执行.而且,根据microsoft文档,异步函数总是在调用者线程中执行(与BeginInvoke相比).这带来了3个下一个问题:

  2. 异步函数在释放给调用函数之前执行了多少?

    async void MyAsyncFunction()
    {
        Operation1();
        Operation2();
        Operation3();
        ....
        Stream s=...;
        await s.WriteAsync(....);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在我读过的有关await/async的文章中,有人说没有等待操作符的异步函数按顺序执行,并且async/await立即返回.但它唠叨着我MyAsyncFunction可能总是执行Operation1 ... Operation3,然后才会发布它await s.WriteAsync.

  3. 如果我Thread.Sleep在async函数中使用如下所示:

    async void DoStuff()
    {
        Stream s=...;
        ...
        await s.WriteAsync(....);
        Thread.Sleep(10000);
        ....
    }
    
    Run Code Online (Sandbox Code Playgroud)

    Thread.Sleep会阻塞执行它的整个线程还是只阻止异步函数?

  4. 如果我semaphore.Wait()在其中一个异步函数中使用它会期望信号量被其他异步函数释放,该怎么办?这会像线程一样运行,还是会导致死锁?

  5. await在异步函数之外不起作用.为什么?

Ste*_*ary 16

我建议你阅读我的async介绍.

这将按预期一直工作(例如写入文件12345 .....而不是13254或其他东西)?

不,你需要await拨打电话WriteAsync.

异步函数在释放给调用函数之前执行了多少?

直到它await的操作尚未完成.

Thread.Sleep会阻塞执行它的整个线程还是只阻止异步函数?

Thread.Sleep- 以及所有其他阻塞方法 - 将阻止async方法和执行它的线程.

作为一般规则,请勿在方法中使用任何阻止方法async.

如果我在其中一个异步函数中使用semaphore.Wait()并且它将期望由另一个异步函数释放信号量,该怎么办?这会像线程一样运行,还是会导致死锁?

这完全取决于你的背景.Wait是一种阻塞方法,因此如果"其他" async方法需要被阻塞方法保存的上下文,那么您将死锁.

请注意,这SemaphoreSlimasync友好的; 你可以用WaitAsync而不是Wait.

await在异步函数之外不起作用.为什么?

因为async关键字启用了await关键字.这样做是为了最大限度地减少新关键字对C#语言和代码可读性的影响.


Adr*_*ura 15

您可以awaitEric Lippert的以下文章中找到有关操作员问题的答案,他说:

"await"运算符......并不意味着"此方法现在会阻止当前线程,直到异步操作返回".这将使异步操作回到同步操作,这正是我们试图避免的.相反,它意味着与此相反; 它意味着"如果我们正在等待的任务尚未完成,那么将该方法的其余部分作为该任务的继续进行注册,然后立即返回给您的呼叫者; 任务将在完成时调用continuation. - Eric Lippert