Mas*_*aus 2 c# async-await c#-5.0
假设我们必须通过异步流向数据库写下1000个元素的列表.是等待1000次异步插入语句,还是将所有1000个插入包装在一个封装到Task.Run语句中的单个同步方法中等待一次?
例如,SqlCommand每个方法都加上他的async版本.在这种情况下,我们有一个insert语句,所以我们可以调用ExecuteNonQuery或ExecuteNonQueryAsync.
通常,在异步/等待指南上,我们读到如果您有某个方法可用的异步版本,则应该使用它.所以我们写一下:
async Task Save(IEnumerable<Savable> savables)
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use asynchronous version
await sqlCmd.ExecuteNonQueryAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码很清楚.但是,每次从await部分出来时,它也会在UI线程上返回,然后在遇到的下一个await中返回后台线程,依此类推(不是吗?).这意味着用户可以看到一些延迟,因为UI线程不断地被继续await执行下一个foreach周期而中断,并且在那段时间内UI冻结了一点.
我想知道我是否更好地编写这样的代码:
async Task Save(IEnumerable<Savable> savables)
{
await Task.Run(() =>
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use synchronous version
sqlCmd.ExecuteNonQuery();
}
});
}
Run Code Online (Sandbox Code Playgroud)
以这种方式,整个foreach在辅助线程上执行,而在UI线程和辅助线程之间没有连续切换.这意味着UI线程可以在整个持续时间内foreach(例如微调器或进度条)自由更新View ,也就是说,用户不会感知到任何延迟.
我对吗?或者我错过了一些关于"异步一直向下"的事情?
我不是在寻找简单的基于意见的答案,我正在寻找async/await指南的解释,以及解决它的最佳方法.
编辑:
我已经读过这个问题,但它不一样.这个问题是关于在await异步方法上选择SINGLE 而不是单个Task.Runawait.这个问题是关于调用1000的后果await以及由于线程之间的连续切换而导致的资源开销.
您的分析基本上是正确的.你似乎高估了这会给UI线程带来的负担; 要求它做的实际工作量相当小,所以很可能它会保持良好状态,但你可能会做得不够,所以你是正确的有兴趣不在UI线程上执行延续.
您当然缺少的是避免UI线程的所有回调的首选方法.当您await进行操作时,如果您实际上不需要方法的其余部分返回到原始上下文,则可以简单地添加ConfigureAwait(false)到您正在等待的任务的末尾.这将阻止继续在当前上下文(即UI线程)中运行,而是让延续在线程池线程中运行.
使用ConfigureAwait(false)允许您避免UI不必要地负责非UI工作,同时还防止您需要调度线程池线程来完成比他们需要做的更多的工作.
当然,如果你在继续之后最终做的工作实际上是要做UI工作,那么该方法不应该使用ConfigureAwait(false);,因为它实际上想要在UI线程上安排延续.
| 归档时间: |
|
| 查看次数: |
806 次 |
| 最近记录: |