c# - 我是否正确认为这个 async-await 示例没有做任何有用的事情?

标签 c# .net asynchronous async-await

我在看一段代码是这样的(我写的是等价的,不是直接复制粘贴的)

public virtual async Task<Something> SomeMethodAsync(string s)
{
   string uri = String.Format(stuff, param);
   Something something;
   HttpResponseMessage responseMsg = await httpClient.GetAsync(uri);
   if(responseMsg.IsSuccessStatusCode)
      response = await responseMsg.Content.ReadAsAsync<Something>(blah);
   else
      throw new CreateException(String.Format(problemo));
   return response;
}

这叫像

    public virtual Something GetSomething(string id)
    {
        return GetOrderAsync(id).Result;
    }

我想知道我对这是否有任何帮助的怀疑是否正确。

自方法

    public virtual Something GetSomething(string id)
    {
        return SomeMethodAsync(id).Result;
    }

不等待 SomeMethodAsync,这意味着当到达 HttpResponseMessage responseMsg = await httpClient.GetAsync(uri); 行时,控制权返回给 GetSomething ,在此期间没有独立的工作可以完成。

此外,还有两个等待

   HttpResponseMessage responseMsg = await httpClient.GetAsync(uri);
   if(responseMsg.IsSuccessStatusCode)
      response = await responseMsg.Content.ReadAsAsync<Something>(blah);

没有完成任何事情,因为第二个取决于第一个的结果。

我说得对吗?

最佳答案

它比无用更糟糕,它是积极有害的:事实上,下面的代码

public virtual Something GetSomething(string id)
{
    return SomeMethodAsync(id).Result;
}

会在多种环境(例如 Windows 窗体)中死锁 - 具体来说,它会在任何具有同步上下文的环境中死锁。这就是 Stephen Cleary 等人的原因。 al. 强烈建议“一直向下”使用异步和 not blocking on async code .

例如,以下 Windows 窗体代码示例也会出现死锁:

private async Task<bool> TryThis()
    {
        Trace.TraceInformation("Starting TryThis");
        await Task.Run(() =>
        {
            Trace.TraceInformation("In TryThis task");
            for (int i = 0; i < 100; i++)
            {
                // This runs successfully - the loop runs to completion
                Trace.TraceInformation("For loop " + i);
                System.Threading.Thread.Sleep(10);
            }
        });

        // This never happens due to the deadlock
        Trace.TraceInformation("About to return");
        return true;
    }

    // Button click event handler
    private void button1_Click(object sender, EventArgs e)
    {
        bool result = TryThis().Result;
        // Never actually gets here
        Trace.TraceInformation("Done with result");
    }

为了解决我对您的更广泛问题的理解,async/await 可以通过以下两种方式之一使用:在单个线程上异步工作或作为在后台线程上工作的更简单方法。通常,您会将第一个用于 I/O 绑定(bind)任务(创建线程只是为了等待结果是没有意义的),第二个用于 CPU 绑定(bind)任务。

简而言之,这些结构只有在允许程序在相同的时间内完成比其他情况下更多的工作时才有用。例如,像这样的东西:

static void Main(string[] args) {
     // This is a terrible thing to do but it's for illustration purposes
     Task task = Method1();
     task.Wait();

     // Some other work
 }

 private static async Task Method1() {
     await Method2();
     // Some other work
 }

 private static async Task Method2() {
     await Method3();
     // Some other work
 }

 private static async Task Method3() {
    await Task.Delay(1000);
 }

那么您基本上只是按顺序运行这些(即使用异步不允许计算机做比其他方式更多的工作),所以在这种情况下没有什么意义。

编辑:当然,在非控制台应用程序中,类似的代码示例可能仍然有用。例如,根据评论,在 Web 服务器中,async/await 可以释放线程来做其他工作。无论哪种方式,关键是 async/await 是有用的,如果,,它允许计算机完成比它本来能够完成的更多的事情;在这个特定示例中,它没有。

关于c# - 我是否正确认为这个 async-await 示例没有做任何有用的事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41110863/

相关文章:

c# - 是否无法在运行时或编译时更改 SSDL 内容(Visual Studio 2015 EntityFramework 数据库首先使用 Oracle)

c# - 在 C# 中使用原始套接字

c# - 使 Guid 属性线程安全

C# BinaryFormatter - 使用另一个命名空间中的对象反序列化

c# - MS Project : where to get started? 的 super 简约插件

.net - 在 linux 上将 dotnet 可执行文件安装到 PATH 中

javascript - 异步更改 javascript 函数/"class"的参数?

c++ - 服务器在已经处理请求时收到请求时崩溃

c++ - boost::asio async_read_some async_read_until 编译器警告

c# - 水平对齐两个按钮 mvc5 razor c#