c# - 使用 DRY 和分而治之原则链接的异步方法

标签 c# .net async-await dry divide-and-conquer

假设我们有以下方法:

private async Task<string> Foo(string parameter)
{
    // Some code to convert source parameter
    string convertedParameter = //value;

    CallResult callResult;
    try
    {
        var integerResult = await LoadInformationAsync(convertedParameter);
        if (integerResult > 0)
        {
            callResult = // Some logic to analyse integerResult and generate CallResult object
        }
        else
        {
            callResult = // Some logic to analyse integerResult and generate CallResult object
        }
    }
    catch (Exception ex)
    {
        callResult = CallResult.Default; // some default value if call failed
    }

    var stringResult = // some logic to convert callResult instance to some another string result;

    return stringResult; //Finally return the result
}

我们不要深入讨论细节。最主要的是,该方法包含一些业务逻辑并调用(假设 3d party)可等待的方法 LoadInformationAsync

这些注释的背后可能是大量的业务逻辑,因此,我认为,每个人都会同意,将逻辑拆分为单独的方法(甚至类)绝对是件好事。

因此,LoadInformationAsync 方法的核心调用将深入调用堆栈。像这样的事情:

private async Task<string> Foo(string parameter)
{
    // Some code to convert source parameter
    string convertedParameter = //value;

    CallResult callResult = await MakeSafeCall(convertedParameter);

    var stringResult = // some logic to convert callResult instance to some another string result;

    return stringResult; //Finally return the result
}

private async Task<CallResult> MakeSafeCall(string parameter)
{
    try
    {
        var integerResult = await LoadInformationAsync(convertedParameter);
        if (integerResult > 0)
        {
            return callResult = // Some logic to analyse integerResult and generate CallResult object
        }
        else
        {
            return callResult = // Some logic to analyse integerResult and generate CallResult object
        }
    }
    catch (Exception ex)
    {
        return CallResult.Default;
    }
}

因此,我们有了稍微好一点的代码。 F.e.某些类/方法可能想要调用方法 MakeSafeCall 来进行 try/catch。

但是我们现在有什么?我们有一个额外的异步方法需要等待。每对 async/await 都会带来一个状态机来捕获上下文等。好吧,我们可以处理这个开销,但是如果我们有更复杂的逻辑(而且我们经常这样做)迫使我们将根方法分成更小的和平,该怎么办?我们的异步/等待对数量将会增加。而且好像不太好。

那么问题是:在这种情况下使用 async/await 的好模式是什么?

最佳答案

我认为 Stephan Toub 在他的文章 Async Performance: Understanding the Costs of Async and Await 中对您的问题给出了很好的答案

Asynchronous methods are a powerful productivity tool, enabling you to more easily write scalable and responsive libraries and applications. It’s important to keep in mind, though, that asynchronicity is not a performance optimization for an individual operation. Taking a synchronous operation and making it asynchronous will invariably degrade the performance of that one operation, as it still needs to accomplish everything that the synchronous operation did, but now with additional constraints and considerations. A reason you care about asynchronicity, then, is performance in the aggregate: how your overall system performs when you write everything asynchronously, such that you can overlap I/O and achieve better system utilization by consuming valuable resources only when they’re actually needed for execution. The asynchronous method implementation provided by the .NET Framework is well-optimized, and often ends up providing as good or better performance than well-written asynchronous implementations using existing patterns and volumes more code. Any time you’re planning to develop asynchronous code in the .NET Framework from now on, asynchronous methods should be your tool of choice.

底线是,不要过早优化。如果您对代码进行基准测试并发现async 方法是瓶颈,请了解其幕后功能以及如何编写代码以更加注重性能。但请记住,.NET 框架团队在实现 async-await 时就考虑到了这一点,您可以在细节中看到这一点,例如将 AsyncTaskMethodBuilder 设为结构体而不是类以减少 GC 压力等。

我建议您仔细阅读stephans的文章,以更好地了解框架所做的成本/优化。

关于c# - 使用 DRY 和分而治之原则链接的异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25386557/

相关文章:

c# - NHibernate 是否应该清除 ISessionFactory.Dispose 上的分布式二级缓存?

c# - 为什么这个 async/await 不会异步运行?

c# - 将异步结果生成给 ASP PartialView

c# - 将输入添加到数组的构造函数

c# - 将类属性公开到 Visual Studio 属性窗口

c# - 加快 ClickOnce 应用程序启动的方法

.net - F# 类型的组合。如何实例化和使用。

c# - Protobuf-net 在序列化期间跳过数据

c# - 根据 USPS 州缩写验证字符串

javascript - React 不会将多个获取的 API 渲染到 DOM