C# 最佳异步while方法
我需要编写一些异步代码,这些代码本质上是试图反复与数据库对话并初始化数据库。通常第一次尝试会失败,因此需要重试 在过去的日子里,我会使用类似的模式:C# 最佳异步while方法,c#,.net,multithreading,async-await,C#,.net,Multithreading,Async Await,我需要编写一些异步代码,这些代码本质上是试图反复与数据库对话并初始化数据库。通常第一次尝试会失败,因此需要重试 在过去的日子里,我会使用类似的模式: void WaitForItToWork() { bool succeeded = false; while (!succeeded) { // do work succeeded = outcome; // if it worked, mark as succeeded, else retr
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;
}
你可以简单地做到这一点:
private async void Form1_Load(object sender, EventArgs e)
{
bool result = await WaitForItToWork();
MessageBox.Show("WaitForItToWork done:" + result.toString()); // true or false
}
然而,这也会使Form1\u Load
成为一种异步方法
[更新]
下面是我试图说明async/await
在这种情况下实际做了什么。我创建了相同逻辑的两个版本,WaitForItToWorkAsync
(使用async/await
)和WaitForItToWorkAsyncTap
(不使用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());
}
//用于测试的假结果()方法
bool output(){return new Random().Next(0,99)>50;}
//使用异步/等待
异步任务WaitForItToWorkAsync()
{
var=false;
而(!成功)
{
succeed=output();//如果成功,则将其设为成功,否则重试
等待任务。延迟(1000);
}
返回成功;
}
//没有异步/等待
任务WaitForItToWorkAsyncTap()
{
var context=TaskScheduler.FromCurrentSynchronizationContext();
var tcs=new TaskCompletionSource();
var=false;
动作闭包=null;
闭包=委托
{
succeed=output();//如果成功,则将其设为成功,否则重试
任务。延迟(1000)。与(代表)继续
{
如果(成功)
tcs.SetResult(成功);
其他的
闭包();
},上下文);
};
//同步启动任务逻辑
//它也可以同步结束!(例如,如果我们使用“Task.Delay(0)”)
闭包();
返回tcs.Task;
}
//启动两个任务并异步处理每个任务的完成
私有void StartWaitForItToWork()
{
WaitForItToWorkAsync().ContinueWith((t)=>
{
Show(“WaitForItToWorkAsync complete:+t.Result.ToString());
},TaskScheduler.FromCurrentSynchronizationContext());
WaitForItToWorkAsyncTap().ContinueWith((t)=>
{
Show(“WaitForItToWorkAsyncTap complete:+t.Result.ToString());
},TaskScheduler.FromCurrentSynchronizationContext());
}
//等待每个任务(StartWaitForItToWorkAsync本身是异步的)
专用异步任务StartWaitForItToWorkAsync()
{
bool result=wait WaitForItToWorkAsync();
Show(“WaitForItToWorkAsync complete:+result.ToString());
结果=等待WaitForItToWorkAsyncTap();
Show(“WaitForItToWorkAsyncTap complete:+result.ToString());
}
关于线程的几句话。这里没有显式创建其他线程。在内部,
Task.Delay()
实现可能使用池线程(我怀疑它们使用),但在这个特定的示例(WinForms应用程序)中,wait
之后的继续将发生在同一UI线程上。在其他执行环境(例如控制台应用程序)中,它可能会在不同的线程上继续。在我看来,Stephen Cleary的著作是理解async/await
线程概念的必读读物。如果任务是异步的,您可以尝试:
async Task WaitForItToWork()
{
await Task.Run(() =>
{
bool succeeded = false;
while (!succeeded)
{
// do work
succeeded = outcome; // if it worked, make as succeeded, else retry
System.Threading.Thread.Sleep(1000); // arbitrary sleep
}
});
}
请参阅。您实际上不需要
waitforwork
方法,只需等待数据库初始化任务:
async Task Run()
{
await InitializeDatabase();
// Do what you need after database is initialized
}
async Task InitializeDatabase()
{
// Perform database initialization here
}
如果有多段代码调用WaitForItToWork
,则需要将数据库初始化包装到任务中,并在所有工作程序中等待它,例如:
readonly Task _initializeDatabaseTask = InitializeDatabase();
async Task Worker1()
{
await _initializeDatabaseTask;
// Do what you need after database is initialized
}
async Task Worker2()
{
await _initializeDatabaseTask;
// Do what you need after database is initialized
}
static async Task InitializeDatabase()
{
// Initialize your database here
}
只需提供另一个解决方案
public static void WaitForCondition(Func<bool> predict)
{
Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(_ =>
{
var result = predict();
// the condition result is false, and we need to wait again.
if (result == false)
{
WaitForCondition(predict);
}
});
}
公共静态void WaitForCondition(Func predict)
{
Task.Delay(TimeSpan.From毫秒(1000)).ContinueWith(=>
{
var结果=预测();
//条件结果为false,我们需要再次等待。
如果(结果==false)
{
等待条件(预测);
}
});
}
我会简单地通过执行this.WaitForItToWork()来调用它吗代码>-异步库会为我处理线程吗?你会像等待这个一样调用它。WaitForItToWork()
,整个调用链必须重构才能支持这个。。。我将详细说明我的答案,包括更多信息。@Chris:你必须记住使用“等待”关键字。经验法则:始终“等待”必须与“异步”函数耦合。所以,你应该做一些事情,比如等待WaitForItToWork();我不想等待它,我想产生这个任务,并继续我所做的我刚刚更新了我的答案,希望它现在更有意义。实际上,您不需要等待(没有什么比阻塞睡眠
)。wait Task.Delay()
的最佳类比可能是计时器事件async/await
只是编译器提供的一种语法糖。在某种程度上,它类似于node.js
,如果您熟悉它的话(尽管node的javascript缺乏语法上的便利性——一切都是通过闭包完成的——在C#中进行委托)。这正是我在回答时想要避免的。也许,我自己遗漏了一件事:://当一个aw
public static void WaitForCondition(Func<bool> predict)
{
Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(_ =>
{
var result = predict();
// the condition result is false, and we need to wait again.
if (result == false)
{
WaitForCondition(predict);
}
});
}