【问题标题】:Why does this sync wrapper over an async method work?为什么这个异步方法上的同步包装器起作用?
【发布时间】:2016-04-06 18:13:43
【问题描述】:

给定:

  • ASP.NET/WCF Web 服务上的旧式非异步 API 方法
  • 新的异步内部库
  • 未来应该使用的新异步 Web API 控制器
  • 只有异步接口的“存储提供者”对象。它的测试在异步运行以及在请求上下文之外同步运行时通过。

“一直异步”选项不在讨论范围内,因为它会破坏向后兼容性。

public class Impl {
    // This works fine when used asynchronously
    public Task<Guid> SaveThingAsync(Thing thingToSave) {
        return await _storageProvider.saveAsync(thingToSave);
    }

    public Guid SaveThing(Thing thingToSave) {
        // "Obviously", this code creates a deadlock when called 
        // from within the request context
        // return SaveThingAsync(thingToSave).Result

        // Not so obviously, this also creates a deadlock
        // return SaveThingAsync(thingToSave)
        //            .ConfigureAwait(false)
        //            .GetAwaiter()
        //            .GetResult()

        // This was deadlocking, but magically stopped
        // return Task.Run(
        //        async () => await SaveThingAsync(thingToSave)
        //                      .ConfigureAwait(false)
        //               ).Result;

        // This one works
        var saveTask = Task.Run(async () => 
                            await SaveThingAsync(thingToSave)));
        var result = saveTask.ConfigureAwait(false).GetAwaiter().GetResult();
        return result;
    }

为什么?

【问题讨论】:

    标签: c# asynchronous task


    【解决方案1】:

    Task.Run 在请求上下文“外部”运行——它只是在线程池上下文中运行。因此,它不会死锁,因为SaveThingAsync 不会在请求上下文中恢复。

    顺便说一句,ConfigureAwait(false) 在那里毫无意义,因为没有要配置的await

    另一方面,“一路异步”仍然应该是一个选项。 WebAPI 和 WCF 客户端不关心他们调用的实现是同步的还是异步的。将同步实现的 WCF 方法更改为异步实现的 WCF 方法对客户端代码是不可见的。

    【讨论】:

    • 嗯,这很烦人。昨天我在运行第一个 Task.Run 示例时遇到了 TaskCancelled 异常。由于我们的客户端不只是使用直接的服务引用,而是使用从我们的接口生成的客户端库,因此更改 SOAP 接口会破坏一切。
    • @Eris 正如斯蒂芬所说,客户无法分辨。这不是兼容性问题。这在这里解释:stackoverflow.com/a/22591516/122718
    • @Eris:第一个(已注释掉的)Task.Run 示例真的,真的 很奇怪。它使我的大脑弯曲,试图弄清楚它会做什么。传递ConfiguredTaskAwaitable 结构不是惯用的。您应该能够在服务器中使用自己的(异步)接口,而不是客户端使用的同步接口 - 不幸的是,这会(逻辑上)重复接口描述。
    猜你喜欢
    • 2011-06-26
    • 2022-01-13
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    相关资源
    最近更新 更多