【问题标题】:Await Task Not returning after completion等待任务完成后不返回
【发布时间】:2016-09-10 03:24:51
【问题描述】:

我遇到了一个任务正在完成但没有返回的问题。我在不同的服务器上有一个网站和一个 Web 服务。该网站调用具有函数 myFunction() 的库的 Web 服务。如果我从 Web 服务服务器上的控制台应用程序调用 myFunction,它将按预期返回。但是,当我从网站调用 Web 服务以调用 myFunction() 时,它将进入“第 3 步”,而不是“第 4 步”。我有以下调用的简化版本。

private string myFunction()
{
    string myStr = myDoWork().GetAwaiter().GetResult();

    return myStr;
}

private async Task<string> myDoWork()
{
    logger.Debug("Step 1");
    string answer = await aFunction();

    logger.Debug("Step 4");

    return answer;
}

public async Task<string> aFunction()
{
    logger.Debug("Step 2");
    return await bFunction(CancellationToken.None);
}

AsyncLock myLock = new AsyncLock();
public Task<string> bFunction(CancellationToken cToken)
{
    return Task.Run(
        async () =>
        {
            using (await myLock(cToken))
            {
                logger.Debug("Step 3");
                result = "Hello";
                return result;
            }
        },
        cToken);
}

我是 async 和 await 的新手,因此我们将不胜感激。

【问题讨论】:

  • 如果可能,myFunction() 也应该是异步的。如果您阻止异步调用,可能会发生奇怪的事情。另外,为什么bFunction 中的Task.Run 业务?
  • 没有理由不在这里执行Step 4
  • @NateBarbettini 我不知道为什么要使用 Task.Run 的东西。我试图尽可能地简化代码,但你确实让我注意到了一个可能很重要的部分。我正在重用为同步任务编写的异步代码。在没有异步内容的情况下重写所有内容将是一项艰巨的任务。
  • 一般来说,混合同步+异步是个坏主意。理想的解决方案是使其全部异步或全部同步。除了您可以摆脱 Task.Run(async () =&gt;{ }) 以大大简化该部分之外,我没有看到您的示例有任何其他问题。
  • 很可能您遇到了死锁,因为您混合了同步和异步代码。 .GetAwaiter().GetResult() 正在同步等待任务完成。请参阅blog.stephencleary.com/2012/07/dont-block-on-async-code.html 了解更多信息

标签: c# asynchronous


【解决方案1】:

这几乎肯定是myFunction() 的僵局。第 4 步计划在主线程上执行,但由于主线程在GetResult() 上等待被阻塞,所以不能执行。

应该更接近这个:

private string myFunction()
{
    // This is NOT good style - you should avoid blocking on the result of a task.
    string myStr = Task.Run(async () => await myDoWork()).GetAwaiter().GetResult();
    return myStr;
}

private async Task<string> myDoWork()
{
    logger.Debug("Step 1");
    string answer = await aFunction();
    logger.Debug("Step 4");
    return answer;
}

public Task<string> aFunction()
{
    logger.Debug("Step 2");
    return bFunction(CancellationToken.None);
}

AsyncLock myLock = new AsyncLock();
public async Task<string> bFunction(CancellationToken cToken)
{
    using (await myLock(cToken))
    {
        logger.Debug("Step 3");
        return "Hello";
    }
}

一般来说,Task.Run() should be called 从可能的最高级别开始。尽可能保持同步,让调用者决定是否要使用后台线程。

【讨论】:

  • 非常感谢!这解决了它。
  • @JesseMcConahie 更好的解决方案是修复您的代码以使 myFunction 异步而不使用 Task.Run.GetResult()
  • @ScottChamberlain 我同意。
  • 今天我也遇到了同样的问题,虽然上面的解决方案对我有用,后来我发现像await _client.PostAsJsonAsync(apiPath, content).ConfigureAwait(false);这样使用 ConfigureAwait(false) 也解决了问题.. @scottChamberlain 可以使用 ConfigureAwait( false) 在进行异步调用时?任务编程新手,如果有人可以在这里提供您的意见,不胜感激。
  • @Mabiyan 可以使用ConfigureAwait(false),只要the rest of the function is safe to run in the background。在await 之后更新 UI 时,它安全的排名第一。
猜你喜欢
  • 2021-08-14
  • 1970-01-01
  • 2015-11-16
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
相关资源
最近更新 更多