gpt4 book ai didi

c# - 最佳异步 while 方法

转载 作者:IT王子 更新时间:2023-10-29 04:34:23 27 4
gpt4 key购买 nike

我需要编写一些异步代码,这些代码本质上是尝试反复与数据库对话并初始化数据库。第一次尝试往往会失败,因此需要重试。

在过去,我会使用类似于以下的模式:

void WaitForItToWork()
{
bool succeeded = false;
while (!succeeded)
{
// do work
succeeded = outcome; // if it worked, mark as succeeded, else retry
Threading.Thread.Sleep(1000); // arbitrary sleep
}
}

我意识到最近 .NET 在异步模式方面发生了很多变化,所以我的问题是这是最好的使用方法还是值得探索 async 东西,如果那么如何在 async 中实现此模式?

更新

澄清一下,我想异步生成这项工作,这样生成它的方法就不必等待它完成,因为它将在服务的构造函数中生成,因此构造函数必须立即返回。

最佳答案

您可以像这样重构该片段:

async Task<bool> WaitForItToWork()
{
bool succeeded = false;
while (!succeeded)
{
// do work
succeeded = outcome; // if it worked, make as succeeded, else retry
await Task.Delay(1000); // arbitrary delay
}
return succeeded;
}

显然,它会给您带来的唯一好处是更有效地使用线程池,因为它并不总是需要整个线程才能使延迟发生。

根据您获得结果的方式,使用async/await可能有更有效的方法来完成这项工作。通常,您可能会有类似 GetOutcomeAsync() 的东西,它会以自然的方式异步调用 Web 服务、数据库或套接字,因此您只需执行 var outcome = await GetOutcomeAsync()

重要的是要考虑到 WaitForItToWork 将被编译器拆分成多个部分,并且来自 await 行的部分将异步继续。 Here's也许是关于它是如何在内部完成的最好的解释。问题是,通常在您的代码的某个位置,您需要同步异步任务的结果。例如:

private void Form1_Load(object sender, EventArgs e)
{
Task<bool> task = WaitForItToWork();
task.ContinueWith(_ => {
MessageBox.Show("WaitForItToWork done:" + task.Result.toString()); // true or false
}, TaskScheduler.FromCurrentSynchronizationContext());
}

你可以简单地这样做:

private async void Form1_Load(object sender, EventArgs e)
{
bool result = await WaitForItToWork();
MessageBox.Show("WaitForItToWork done:" + result.toString()); // true or false
}

然而,这也会使 Form1_Load 成为异步方法。

[更新]

下面是我试图说明 async/await 在这种情况下实际做了什么。 我创建了相同逻辑的两个版本,WaitForItToWorkAsync(使用 async/await)和 WaitForItToWorkAsyncTap(使用 TAP pattern 而不使用 async/await)。与第二个版本不同,第一个版本非常简单。因此,虽然 async/await 主要是编译器的语法糖,但它使异步代码更易于编写和理解。

// fake outcome() method for testing
bool outcome() { return new Random().Next(0, 99) > 50; }

// with async/await
async Task<bool> WaitForItToWorkAsync()
{
var succeeded = false;
while (!succeeded)
{
succeeded = outcome(); // if it worked, make as succeeded, else retry
await Task.Delay(1000);
}
return succeeded;
}

// without async/await
Task<bool> WaitForItToWorkAsyncTap()
{
var context = TaskScheduler.FromCurrentSynchronizationContext();
var tcs = new TaskCompletionSource<bool>();
var succeeded = false;
Action closure = null;

closure = delegate
{
succeeded = outcome(); // if it worked, make as succeeded, else retry
Task.Delay(1000).ContinueWith(delegate
{
if (succeeded)
tcs.SetResult(succeeded);
else
closure();
}, context);
};

// start the task logic synchronously
// it could end synchronously too! (e.g, if we used 'Task.Delay(0)')
closure();

return tcs.Task;
}

// start both tasks and handle the completion of each asynchronously
private void StartWaitForItToWork()
{
WaitForItToWorkAsync().ContinueWith((t) =>
{
MessageBox.Show("WaitForItToWorkAsync complete: " + t.Result.ToString());
}, TaskScheduler.FromCurrentSynchronizationContext());

WaitForItToWorkAsyncTap().ContinueWith((t) =>
{
MessageBox.Show("WaitForItToWorkAsyncTap complete: " + t.Result.ToString());
}, TaskScheduler.FromCurrentSynchronizationContext());
}

// await for each tasks (StartWaitForItToWorkAsync itself is async)
private async Task StartWaitForItToWorkAsync()
{
bool result = await WaitForItToWorkAsync();
MessageBox.Show("WaitForItToWorkAsync complete: " + result.ToString());

result = await WaitForItToWorkAsyncTap();
MessageBox.Show("WaitForItToWorkAsyncTap complete: " + result.ToString());
}

关于线程的几句话。这里没有明确创建额外的线程。在内部,Task.Delay() 实现可能使用池线程(我怀疑他们使用 Timer Queues ),但在这个特定示例(WinForms 应用程序)中,await 之后的继续> 将发生在同一个 UI 线程上。在其他执行环境(例如控制台应用程序)中,它可能会在不同的线程上继续。国际海事组织,this article Stephen Cleary 的著作是了解async/await 线程概念的必读书籍。

关于c# - 最佳异步 while 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18587628/

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