gpt4 book ai didi

c# - 使用 async/await 的最佳实践

转载 作者:太空狗 更新时间:2023-10-29 21:08:40 24 4
gpt4 key购买 nike

假设我有以下类定义:

public class Calculator
{
public CalculatorResult Calculate()
{
return LongRunningCalculation();
}

private CalculatorResult LongRunningCalculation()
{
return new CalculatorResult(0.00);
}
}

public class ClassThatUsesACalculator
{
private readonly Calculator calculator;

public ClassThatUsesACalculator()
{
this.calculator = new Calculator();
}

public void DoWork()
{
for (int i = 0; i < 10; i++)
{
var result = calculator.Calculate();

DoSomethingWithCalculationResult(result);

DoLightWork();

OnProgressChanged();
}
}
}

public partial class Form : Form
{
public Form()
{
InitializeComponent();
}

private void Method(object sender, EventArgs e)
{
DoWork();
}

private void DoWork()
{
var calculator = new ClassThatUsesACalculator();
calculator.ProgressChanged += (s, e) =>
{
// Update progressbar
};

calculator.DoWork();
}
}

如果我想完成在 DoWork() 中完成的工作,在表单上,​​我可以异步添加一个返回任务的方法 (GetCalculationTask) Task.Run() 并添加一个异步事件处理程序,即对于一个按钮 (MethodOne)。

如果我错了,请纠正我,但在我看来,当 ClassThatUsesACalculatorCalculator 类驻留在我不熟悉的库中时,这将是唯一的选择'拥有。

private Task GetCalculationTask(IProgress<CalculatorProgress> progress)
{
var calculator = new ClassThatUsesACalculator();
calculator.ProgressChanged += (s, e) =>
{
progress.Report(new CalculatorProgress(0));
};

return Task.Run(() =>
{
calculator.DoWork();
});
}

private async void MethodOne(object sender, EventArgs e)
{
IProgress<CalculatorProgress> progress = new Progress<CalculatorProgress> (UpdateProgressBar);

await GetCalculationTask(progress);
}

在我确实拥有图书馆的情况下,我认为还有两个选项,其中一个与第一个非常相似。可能是自己理解不够吧。

ClassThatUsesACalculator 上创建一个封装 DoWork() 方法的方法,然后从表单上的异步方法调用它。

或者,

  1. Task.Run() 封装 Calculator 类上的 LongRunningCalculation()

    public Task<CalculatorResult> CalculateAsync()
    {
    return Task.Run(() =>
    {
    return LongRunningCalculation();
    });
    }
  2. ClassThatUsesACalculator 上创建一个等待新创建方法的调用的异步方法。

    public async Task DoWorkAsync()
    {
    for (int i = 0; i < 10; i++)
    {
    var result = await calculator.CalculateAsync();

    DoSomethingWithCalculationResult(result);

    DoLightWork();

    OnProgressChanged();
    }
    }
  3. 在表单上创建一个异步方法(MethodThree)

    private async void MethodThree(object sender, EventArgs e)
    {
    IProgress<CalculatorProgress> progress = new Progress<CalculatorProgress>(UpdateProgressBar);

    var calculator = new ClassThatUsesACalculator();
    calculator.ProgressChanged += (s, args) =>
    {
    progress.Report(new CalculatorProgress(0));
    };

    await calculator.DoWorkAsync();
    }

现在,在我看来,最后一个选项是最好的,因为我会保持更多的控制权。但也许我离题太远了,希望有人对此提出意见或指示,因为我只能找到关于如何使用异步的解释,但从来没有真正找到如何构建供其他人使用的方法。

最佳答案

作为一般规则,推送任何 Task.Run尽可能在调用堆栈中使用。

您要避免的是具有使用Task.Run 实现的异步签名的方法。在可重用的组件中。那是一个说谎的 API。我有一个 blog post on the subject更详细。

如果您控制相关类,我建议使用 IProgress<T>而不是进度更新事件。 IProgress<T>适用于同步代码和异步代码:

public void DoWork(IProgress<CalculatorProgress> progress = null)
{
for (int i = 0; i < 10; i++)
{
var result = calculator.Calculate();

DoSomethingWithCalculationResult(result);

DoLightWork();

if (progress != null)
progress.Report(new CalculatorProgress(...));
}
}

然后使用它就非常简单了:

private async void MethodTwo(object sender, EventArgs e)
{
IProgress<CalculatorProgress> progress = new Progress<CalculatorProgress>(UpdateProgressBar);

var calculator = new ClassThatUsesACalculator();

await Task.Run(() => calculator.DoWork(progress));
}

保留 Task.Run在需要它的组件(UI 层)和业务逻辑之外使用。

关于c# - 使用 async/await 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25552860/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com