Pin*_*ong 5 c# task-parallel-library xamarin.android async-await xamarin
我遇到了以下有关何时何地使用的文章ConfigureAwait(false),但无法得到答案。
您不需要 ConfigureAwait(false),但仍可在库和 UI 应用程序中使用它。(例如 Xamarin、WinForms 等)
https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html
此链接说相反的答案
为所有服务器端代码调用 ConfigureAwait 的最佳实践
我的问题:
场景 1:下面的代码作为后台服务运行。
我的问题:ConfigureAwait(false)无论何时await都需要像下面的 A 和 B 一样使用:
[Service(Name = "com.MainApplicationService", Label = "Main Application Service", Exported = false)]
public class MainApplicationService : Android.App.Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
await InitAsync().ConfigureAwait(false); //line A
Task.Run(async () => await InitAsync().ConfigureAwait(false)); //line B
return StartCommandResult.Sticky;
}
}
Run Code Online (Sandbox Code Playgroud)
场景 2:下面的代码作为 UI 线程而不是后台服务运行
同样的问题:ConfigureAwait(false)每当使用 await 时都需要,就像下面的 C 和 D 一样:
public class StartupActivity : Android.App.Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
await InitAsync().ConfigureAwait(false); //line C
Task.Run(async () => await InitAsync().ConfigureAwait(false)); //line D
Finish();
}
}
Run Code Online (Sandbox Code Playgroud)
Xamarin Android 版本 8,我认为它是 .net 标准。
https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md
也许这是一个不受欢迎的观点,但现在我ConfigureAwait(false)什至在图书馆也不使用,请参阅:
《重访Task.ConfigureAwait(continueOnCapturedContext: false)》
IMO,如果使用基于 - 的 API 的代码Task关心当前同步上下文以及它可能如何影响该 API 的行为(死锁、冗余上下文切换等),它可以显式地包装 API 调用Task.Run或使用类似TaskExt.WithNoContextfrom的内容上面的链接:
await Task.Run(() => InitAsync());
// or
await TaskExt.WithNoContext(() => InitAsync());
Run Code Online (Sandbox Code Playgroud)
但在大多数情况下,特别是对于 UI 应用程序(有同步上下文,但线程可扩展性不是问题),可以保持原样,不带Task.Runor ConfigureAwait:
await InitAsync();
Run Code Online (Sandbox Code Playgroud)
这将使您有机会发现并调查潜在的死锁,然后再尝试使用ConfigureAwait(false)或缓解它们Task.Run。
因此,继续使用相同的同步上下文并不总是async void一个坏主意,特别是在将未处理的异常发布到当前同步上下文的方法内部,请参阅TAP 全局异常处理程序。
await Task.Run(() => InitAsync());和Task.Run(async () => await InitAsync());和有什么区别await Task.Run(async () => await InitAsync());
在这种情况下(一个简单的asynclambda to Task.Run),差异只是 async/await 编译器生成的状态机的额外开销,您不需要。无论哪种方式,由 返回的任务InitAsync都将自动解开。Task.Run对于更一般的情况,请参阅“await Task.Run();之间的任何区别” return;”和“返回Task.Run()”? ”。
async仅当我需要在完成后执行其他操作时,我才会在此处使用lambda InitAsync,同时仍然不必担心同步上下文,例如:
await Task.Run(async() => {
await InitAsync();
// we're on a pool thread without SynchronizationContext
log("initialized");
});
Run Code Online (Sandbox Code Playgroud)
双重检查:使用像这样的丢弃
_ = WorkAsync();来抑制警告,但它不会捕获异常。为了处理异常,我需要定义一个扩展方法,例如Forget. 关于 即发即忘方法
是的,这就是我的“一劳永逸”的选择。然而,我不认为你InitAsync的情况是真正的“一劳永逸”。也许,最好在类实例中跟踪它:_task = InitAsync()并_task稍后观察。
或者,更好的是,您可以async void在内部使用辅助方法OnCreate来观察以下结果/异常InvokeAsync:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
async void function invokeInitAsync()
{
try
{
await InitAsync();
Finish();
}
catch(Exception e) {
// handle the failure to initialize
await promptAndExitUponErrorAsync(e);
}
}
invokeInitAsync();
}
Run Code Online (Sandbox Code Playgroud)
可能可以创建OnCreateself async void,但是异常(如果有)base.OnCreate()不会同步传播到覆盖的调用者,这可能会产生其他副作用。因此,我将使用一个辅助async void方法,它也可以是本地的,如上所述。
最后,考虑在您的层中拥抱异步ViewModel,然后您就不必在像OnCreate. 有关更多详细信息,请参阅:“如何在 WPF 中使用异步初始化对 ViewModel 进行单元测试”。
| 归档时间: |
|
| 查看次数: |
736 次 |
| 最近记录: |