【问题标题】:Is it possible to stop using async and await where required是否可以停止使用异步并在需要时等待
【发布时间】:2018-05-02 08:07:46
【问题描述】:

我正在实现来自使用异步函数的开发人员的代码。

例子:

public async Task<string> GetDataAsync(string jsonString = "")
{
    string url = $"{this.url}";

    using (HttpClient httpClient = new HttpClient())
    {
        using (StringContent body = new StringContent(jsonString, Encoding.UTF8, "application/json"))
        {
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);

            using (HttpResponseMessage response = await httpClient.PostAsync(url, body))
            {
                switch (response.IsSuccessStatusCode)
                {
                    case true:

                        return await response.Content.ReadAsStringAsync();

                    default:

                        throw new Exception($"Error calling url: {url}. HTTP status: {response.StatusCode}");

                }
            }
        }
    }
}

而且我不需要,也不想异步调用任何东西。但问题是异步函数在我的函数中一直冒泡,所以我不能停止使用它,而且由于 HttpClient 没有使用 Post() 函数而不是 PostAnync() ,所以我觉得卡住了在这个异步笼子里。

有什么技巧可以正常调用异步函数,阻止线程在所有父函数中冒泡吗?

或者是找到没有异步功能的包的唯一解决方案?

【问题讨论】:

  • Task.Run(GetDataAsync).Result 可能是您正在寻找的。它一直等到异步调用完成。
  • 那么你不是阻塞了异步代码,这可能会导致你陷入僵局吗?
  • 这里真正的问题是:为什么你觉得你不需要/或不想使用 async ?当您想要创建可扩展的应用程序时,您需要这样做
  • this is a webapplication 只是让异步传播,并与 2018 年同步,尽可能使用 ConfigureAwait(false)
  • 首先异步并不意味着并行。异步执行将有价值的线程池线程从外部资源阻塞中解放出来,没有复杂性或性能成本。这意味着同一台 IIS 机器可以处理更多并发请求,即它通常更具可扩展性

标签: c# multithreading asynchronous


【解决方案1】:

简短的回答是 - 不,没有通用的方法可以从基于任务的异步函数中创建同步函数。

问题是你不知道它是如何在内部实现的。比如说,异步函数是使用async 实现的,它(部分)在主线程的上下文中运行。然后,如果调用者代码试图通过阻塞调用来阻塞主线程,那么async 函数也会被阻塞,从而导致死锁。

但是,在您的特定情况下,您可以尝试创建一个新任务,从该任务调用async 函数并获取其结果。它很有可能会起作用,但不能保证(如上所述)。

代码如下所示:

using (var response = Task.Run(() => httpClient.PostAsync(url, body).Result).Result)
{
    ...
}

【讨论】:

  • 这将阻塞整个 ThreadPool 线程。此外,据我所知,在任务内部阻塞具有未定义的行为。还有一件事,这个“响应”实际上是一个任务,因为你没有等待它,所以它甚至不会编译。
  • @FCin 阻止线程池中的线程是可以的,我专门为此使用该线程。感谢您的第二条评论 - 我更正了代码。
  • 多次调用这个方法是不行的。每次它都会安排另一个线程池线程,导致它完全阻塞 ThreadPool 并使您的应用程序有一段时间无响应。
  • 在没有ConfigureAwait的情况下调用.Result会使你的asp.net应用程序死锁,因为Task会等待SynchronizationContext(UI)线程空闲,但它永远不会空闲,因为它会等待任务完成。
  • @FCin 我的代码一次不会使用线程池中的多个线程。我不明白你所说的“阻止线程池”是什么意思。
猜你喜欢
  • 1970-01-01
  • 2020-01-28
  • 2014-07-04
  • 2019-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
相关资源
最近更新 更多