代码之家  ›  专栏  ›  技术社区  ›  Jiji

是什么让这些异步方法调用不同?

  •  0
  • Jiji  · 技术社区  · 6 年前

    我在读C#book中关于等待和异步关键字的一章。 它主要解释了这类方法调用,调用方使用wait关键字等待被调用的方法完成。

    在这个简单的例子中,我看不到这三个调用的优点,但更重要的是,它们没有区别。有人能解释一下它对应用程序流程的影响吗?它是否只有在调用线程是主GUI线程时才有用?

    static async Task Main(string[] args)
    {
        WriteText();
    
        await WriteTextAsync();
    
        WriteTextAsync().Wait();
    }
    
    static void WriteText()
    {
        Thread.Sleep(3_000);
        Console.WriteLine("Hello");
    }
    
    static async Task WriteTextAsync()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(3_000);
            Console.WriteLine("Hello");
        });
    }
    

    Ps:如果该方法的调用线程正在等待该方法以任何方式完成,那么它也可能是一个正常的调用?

    3 回复  |  直到 6 年前
        1
  •  1
  •   Moshi    6 年前

    我对你问题的理解是

    如果程序在中等待响应 等待WriteTextAsync() 那有什么好处呢?

    对于客户端应用程序,如Windows应用商店、Windows桌面和Windows Phone应用程序,异步的主要好处是响应能力。这些类型的应用程序使用async主要是为了保持UI的响应性。对于服务器应用程序,异步的主要好处是可伸缩性。

    我将尝试从web应用程序的角度进行解释。

    假设您有一个web应用程序,当客户端启动ASP请求时,它依赖于外部资源,比如数据库调用。NET获取其一个线程池线程并将其分配给该请求。因为它是同步写入的,所以请求处理程序将同步调用该外部资源。这会阻止请求线程,直到对外部资源的调用返回。图1展示了一个包含两个线程的线程池,其中一个线程在等待外部资源时被阻塞。

    enter image description here

    图1同步等待外部资源

    现在,如果第三个客户端同时请求,那么线程池中就没有线程可以分配第三个请求。

    在异步调用中,线程不会被卡住,而是会被释放并返回到线程池,这将有助于为第三次调用提供服务。

    当请求服务器活动结束时,链接数据库调用结束 SynchronizationContext 恢复通话,并将休息状态返回给客户。

    在aync呼叫的简单类比中的吼叫图像

    enter image description here

    有很多事情在幕后发生。我是从 Async Programming : Introduction to Async/Await on ASP.NET 还有我的理解。强烈建议在使用前要有清楚的了解 async-wait .

        2
  •  0
  •   Camilo Terevinto Chase R Lewis    6 年前

    我指的是:

    //Call 1
    WriteText();
    
    //Call 2    
    await WriteTextAsync();
    
    //Call 3
    WriteTextAsync().Wait();
    

    如果您想做的是同步等待,那么第一个调用没有任何问题。在控制台应用程序中,这是很正常的。

    这个问题出现在带有UI的程序中,或者需要最佳利用CPU资源的程序中,最常见的情况是web应用程序。

    拨打2,使用 await 执行异步等待的结果 WriteTextAsync .就其本身而言,这是正常的。然而 WriteTextAsync 这是一个很好的例子 从不 做:

    static async Task WriteTextAsync()
    {
        // Let's create a Thread
        await Task.Run(() =>
        {
            // just to block it completely, having it do nothing useful
            Thread.Sleep(3_000);
            Console.WriteLine("Hello");
        });
    }
    

    相反,作者应该使用:

    static async Task WriteTextAsync()
    {
        // Let's *not* create a new thread
        await Task.Delay(3_000);
        Console.WriteLine("Hello");
    }
    

    也许他们会进一步指出这一点,但你没有给我们书名让我们知道这一点。

    当调用方法不能是 async 一个,你必须打电话给一个 异步的 方法,所以:

    // Think that for some reason you cannot change the signature, 
    // like in the case of an interface, and an async void would make your code
    // never complete correctly
    static void Main(string[] args)
    {
        //Call 3
        WriteTextAsync().Wait();
    }
    

    总的来说,我建议你找一本更好的书。当实际需要异步代码时,示例更容易理解。

        3
  •  0
  •   Seva    6 年前

    当你说 WriteText() , WriteText() 将阻止当前线程,直到它完成,因为它是同步的。

    当你说 await WriteTextAsync() ,您将生成一个新线程,并且不会阻止不依赖于线程结果的计算 WriteTextAsync() .
    编辑:根据 Microsoft Docs 当你说 等待WriteTextAsync() ,编译器会安排剩余的 Main() 之后处决 WriteTextAsync() 完成。然后,应该将控件返回给异步方法的调用方。但谁是电话的来电者 Main() ? 事实上 turns out ,没有 async Main() -实际上是一样的 Main() -而这只是不写作的语法糖分 .Wait() 里面。所以在这种情况下,这个调用相当于 WriteTextAsync().Wait() !

    最后,当你说 WriteTextAsync()。等等 ,则再次阻止当前线程,并等待 WriteTextAsync() .