4

在类库中公开 API 的同步和异步版本是否有推荐的最佳实践/指南?例如,如果我在类库中定义了以下 2 个方法:

  public Task<string> GetSomeDataAsync()
    {
        //typically an IO operation that would be awaited on, simplified to return a Task for illustration
        return Task<string>.Factory.StartNew( () =>  "foo");
    }

    public string GetSomeDataSync()
    {
        var task = GetSomeDataAsync();
        task.ConfigureAwait(continueOnCapturedContext: false);
        return task.Result;
    }

以上可以托管在 Winform/WPF/Console/ASP.NET 客户端应用程序中。考虑到任务被配置为不捕获任何同步上下文以避免潜在的死锁,客户端使用上面使用 task.Result 的同步版本是否安全

4

2 回答 2

4

我认为这方面最好的建议来自 Stephen Toub 的两篇文章:

第二个更适合你。简而言之,它说你不应该这样做。如果您的方法的调用者决定同步等待,他仍然可以做出选择,并且他比您处于更好的位置(因为他知道环境,所以他应该知道死锁是否是一个问题,例如)。

以上可以托管在 Winform/WPF/Console/ASP.NET 客户端应用程序中。考虑到任务被配置为不捕获任何同步上下文以避免潜在的死锁,客户端使用上面使用 task.Result 的同步版本是否安全

你错了。ConfigureAwait()不会Task以任何方式修改 (尤其是因为此时Task已经在执行)。它所做的只是返回一个ConfiguredTaskAwaitable,如果你await这样做,它将不会在捕获的上下文中恢复。

这意味着您的方法仍然会死锁。

于 2013-06-07T10:42:23.613 回答
-1

MS 认可的异步模式有 3 个“主要”选项。我建议您选择其中一种模式并遵守它...看起来您已经朝着“基于任务的异步模式”迈进,因此您只需很少的模组即可符合该模式. 这允许您以一种对其他消费者来说统一且直观的方式创建您的方法......他们将从 MS 构建的 .NET 库中了解模式。有关详细信息,请参阅此:

概述:http: //msdn.microsoft.com/en-us/library/jj152938.aspx

任务异步模式:http: //msdn.microsoft.com/en-us/library/hh873175.aspx

使用支持取消令牌的任务异步模式的方法示例:

public Task<string> GetSomeDataAsync(CancellationToken cancellationToken = null)
{
    return Task<string>.Factory.StartNew(() =>  "foo", cancellationToken);
}

// NOTE: no need to append Sync to the method name, redundant.
public string GetSomeData()
{
    var task = GetSomeDataAsync();
    task.ConfigureAwait(continueOnCapturedContext: false);
    return task.Result;
}
于 2013-06-07T05:21:57.937 回答