在没有等待 #2 的情况下调用异步方法

Posted

技术标签:

【中文标题】在没有等待 #2 的情况下调用异步方法【英文标题】:call async method without await #2 【发布时间】:2013-11-16 04:14:17 【问题描述】:

我有一个异步方法:

public async Task<bool> ValidateRequestAsync(string userName, string password)

    using (HttpClient client = new HttpClient())
    
        HttpResponseMessage response = await client.GetAsync(url);
        string stringResponse = await response.Content.ReadAsStringAsync();

        return bool.Parse(stringResponse);
    

我这样称呼这个方法:

bool isValid = await ValidateRequestAsync("user1", "pass1");

我可以从同步方法中调用相同的方法,而不使用await 关键字吗?

例如:

public bool ValidateRequest(string userName, string password)

    return ValidateRequestAsync(userName, password).Result;

我认为这会导致死锁。

编辑

调用上述方法会使调用永远不会结束。 (方法不再结束)

【问题讨论】:

我相信在没有 await 的情况下调用异步方法只会导致该方法被同步调用,结果行为将取决于您的方法实际执行的操作。 我试过了!看起来方法调用永远不会结束 @Chris 该方法总是被同步调用。它只是返回一个任务,这是唯一的区别。所有的魔法都在等待中,而不是在通话中。 啊,我明白了,我还没有真正使用过异步;我需要去阅读更多关于机制的信息。谢谢。 您的方法可能会死锁,但这是您的逻辑的结果,而不是您以同步方式调用它的事实。 【参考方案1】:

如果从单线程执行上下文(如 UI 线程)调用异步方法,并同步等待结果,则很有可能发生死锁。在您的示例中,该概率为 100%

考虑一下。当你打电话时会发生什么

ValidateRequestAsync(userName, password).Result

您调用方法 ValidateRequestAsync。在那里你调用 ReadAsStringAsync。结果是一个任务将返回给 UI 线程,并计划在它可用时继续在 UI 线程上执行的延续。但当然,它永远不会变得可用,因为它正在等待(阻塞)任务完成。但任务无法完成,因为它正在等待 UI 线程变得可用。死锁。

有一些方法可以防止这种僵局,但它们都是一个坏主意。为了完整起见,以下方法可能有效:

Task.Run(async () => await ValidateRequestAsync(userName, password)).Result;

这是个坏主意,因为你仍然会阻塞你的 UI 线程等待并且没有做任何有用的事情。

那么解决办法是什么?一路异步。 UI 线程上的原始调用者可能是某个事件处理程序,因此请确保它是异步的。

【讨论】:

知道了。解决方案是创建一个 Sync 和一个 Async 方法? 某些 asp.net web api 操作过滤器不支持异步方法 @RaraituL 这是真的,.ConfigureAwait 可能会帮助你。但要小心:动作过滤器应该运行得很快。使用.Result 会阻塞线程,这是应该避免的,在动作过滤器中也是如此。 不,task.ConfigureAwait(false).Result 肯定行不通。它甚至不会编译,因为 ConfigureAwait() 不会返回 Task 就我而言,我不在乎它是否阻塞了主线程——它是每周手动启动一次的进程——很好的答案【参考方案2】:

你可以使用return ValidateRequestAsync(userName, password).GetAwaiter().GetResult();

【讨论】:

哦,这真的很好看,值得更多的支持。 这似乎不起作用。进程挂起,就像您执行 ValidateRequestAsync(userName, password).Result 一样。 Kris 回应的“坏主意”起到了作用:Task.Run(async () => await ValidateRequestAsync(userName, password)).Result【参考方案3】:

对我来说,它在异步调用中使用 .ConfigureAwait(false) 设置。我有类似的东西

return await Entities.SingleOrDefaultAsync(.....).ConfigureAwait(false);

【讨论】:

以上是关于在没有等待 #2 的情况下调用异步方法的主要内容,如果未能解决你的问题,请参考以下文章

C# 中有没有办法在不使调用者也异步的情况下调用异步方法? [复制]

如何正确使用等待和通知方法?

java同异步请求和阻塞非阻塞的区别

如何使用回调在任何函数中调用异步等待方法

在没有等待的情况下使用异步?

异步调用