异步是否会在此示例中带来任何好处?

时间:2017-07-24 13:43:35

标签: c# .net asynchronous async-await

我试图在C#中学习asyncawait机制。

simplest example对我很清楚。

该行

Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

触发异步Web调用。控件返回AccessTheWebAsync()。可以免费执行DoIndependentWork()。执行此操作后,它等待任务getStringTask的完成,当此结果可用时,该函数执行下一行 return urlContents.Length; 因此,据我所知,async调用的目的是让调用者在使用async标记的操作正在进行时执行其他操作。

但是,我在此功能中对example感到困惑。

    private async Task<byte[]> GetURLContentsAsync(string url)
    {
        // The downloaded resource ends up in the variable named content. 
        var content = new MemoryStream();

        // Initialize an HttpWebRequest for the current URL. 
        var webReq = (HttpWebRequest)WebRequest.Create(url);

        // Send the request to the Internet resource and wait for 
        // the response.                 
        using (WebResponse response = await webReq.GetResponseAsync())

        // The previous statement abbreviates the following two statements. 

        //Task<WebResponse> responseTask = webReq.GetResponseAsync(); 
        //using (WebResponse response = await responseTask)
        {
            // Get the data stream that is associated with the specified url. 
            using (Stream responseStream = response.GetResponseStream())
            {
                // Read the bytes in responseStream and copy them to content. 
                await responseStream.CopyToAsync(content);

                // The previous statement abbreviates the following two statements. 

                // CopyToAsync returns a Task, not a Task<T>. 
                //Task copyTask = responseStream.CopyToAsync(content); 

                // When copyTask is completed, content contains a copy of 
                // responseStream. 
                //await copyTask;
            }
        }
        // Return the result as a byte array. 
        return content.ToArray();
    }

在方法GetURLContentsAsync()内,有两个异步调用。但是,API会同时调用await。调用者在<{1}}操作的触发器和数据接收之间之间没有做任何事情。所以,据我所知,async机制在这里没有任何好处。我错过了一些明显的东西吗?

3 个答案:

答案 0 :(得分:5)

您的代码无需在await异步调用之间明确执行任何操作即可获得收益。这意味着线程没有等待每个调用完成,可以进行其他工作。

如果这是一个Web应用程序,它可能会导致处理更多请求。如果它是Windows应用程序,则意味着UI线程未被阻止,用户可以获得更好的体验。

答案 1 :(得分:2)

  

但是,API会在两者上等待调用。

您必须等待两者,因为您的方法代码应该按顺序执行,如果您没有等待第一次调用,您的下一行代码也将被执行,这是您可能不会期望或需要发生的事情

在我的脑海中,等待这两种方法的两个原因是:

  • 您的第一个异步方法结果可能会被用作 第二个异步方法调用中的参数

  • 我们也可能决定第一次异步的结果 方法调用要调用的第二个异步方法

因此,如果是这种情况,那么很明显为什么您不需要在await方法中的每个异步方法调用中添加async

编辑:

从您明确指出的示例中可以看到第一个异步方法的输出正在第二个异步方法调用中使用:

using (WebResponse response = await webReq.GetResponseAsync())

            // The previous statement abbreviates the following two statements. 

            //using (WebResponse response = await responseTask)
            {
                // Get the data stream that is associated with the specified url. 
                using (Stream responseStream = response.GetResponseStream())
                {
                    // Read the bytes in responseStream and copy them to content. 
                    await responseStream.CopyToAsync(content);

                    // The previous statement abbreviates the following two statements. 

                    // CopyToAsync returns a Task, not a Task<T>. 
                    //Task copyTask = responseStream.CopyToAsync(content); 

                    // When copyTask is completed, content contains a copy of 
                    // responseStream. 
                    //await copyTask;
                }
            }

答案 2 :(得分:0)

GetResponseAsync在Web服务器启动响应时(通过发送标头)返回,而CopyToAsync在从服务器发送所有数据并将其复制到另一个流后返回。

如果添加代码来记录异步调用开始和函数返回之间经过的时间,您将看到两种方法都需要一些时间才能完成(至少在大文件上)。 )

private static async Task<byte[]> GetURLContentsAsync(string url) {
    var content = new MemoryStream();

    var webReq = (HttpWebRequest)WebRequest.Create(url);

    DateTime responseStart = DateTime.Now;
    using (WebResponse response = await webReq.GetResponseAsync()) {
        Console.WriteLine($"GetResponseAsync time: {(DateTime.Now - responseStart).TotalSeconds}");

        using (Stream responseStream = response.GetResponseStream()) {
            DateTime copyStart = DateTime.Now;
            await responseStream.CopyToAsync(content);
            Console.WriteLine($"CopyToAsync time: {(DateTime.Now - copyStart).TotalSeconds}");
        }
    }

    return content.ToArray();
}

对于快速服务器上的~40 MB文件,第一个await是快速的,而第二个await需要更长的时间。

https://ftp.mozilla.org/pub/thunderbird/releases/52.2.1/win32/en-US/Thunderbird%20Setup%2052.2.1.exe
GetResponseAsync time: 0.3422409
CopyToAsync time: 5.3175731

但对于需要一段时间才能响应的服务器,第一次等待也需要一段时间。

http://www.fakeresponse.com/api/?sleep=3
GetResponseAsync time: 3.3125195
CopyToAsync time: 0