我目前正在开发一个使用TAP的大部分异步应用程序。每个有产卵方法的类 Task
还有一个 TaskScheduler
注入其中。这允许我们执行任务的显式调度,据我所知,这不是Microsoft使用Async CTP的方式。
我对新方法(隐式调度)的唯一问题是我们以前的哲学一直是“我们知道延续将始终指定他们的任务调度程序,所以我们不需要担心我们完成任务的上下文” 。
远离它确实让我们感到担心,因为它在避免细微的线程错误方面效果非常好,因为对于每一段代码我们都可以看到编码器已经记住要考虑他所使用的线程。如果他们错过了指定任务调度程序,那就是一个错误。
问题1: 任何人都可以向我保证隐含的方法是个好主意吗?我看到ConfigureAwait引入了很多问题(false)以及传统/第三方代码中的显式调度。例如,我怎样才能确定我的'await-ridden'代码总是在UI线程上运行?
问题2: 所以,假设我们删除所有 TaskScheduler
从我们的代码DI开始使用隐式调度,我们如何设置默认的任务调度程序?如何在等待昂贵的方法之前通过方法中途更改调度程序,然后再将其重新设置?
(p.s.我已经读过了 http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/configuring-waiting.aspx)
我会小心翼翼地回答。 ;)
问题1:任何人都可以向我保证隐含的方法是个好主意吗?我看到ConfigureAwait引入了很多问题(false)以及传统/第三方代码中的显式调度。例如,我怎样才能确定我的'await-ridden'代码总是在UI线程上运行?
规则 ConfigureAwait(false)
非常简单:如果您的方法的其余部分可以在线程池上运行,则使用它,如果您的方法的其余部分必须在给定的上下文中运行(例如,UI上下文),则不要使用它。
一般来说, ConfigureAwait(false)
应该由库代码使用,而不是由UI层代码(包括UI类型层,如MVVM中的ViewModels)使用。如果该方法是部分后台计算和部分UI更新,则应将其拆分为两种方法。
问题2:因此,假设我们从代码中删除所有TaskScheduler DI并开始使用隐式调度,那么我们如何设置默认任务调度程序?
async
/await
通常不会使用 TaskScheduler
;他们使用“调度上下文”概念。这实际上是 SynchronizationContext.Current
,并回归 TaskScheduler.Current
只有没有 SynchronizationContext
。因此,可以使用替换您自己的调度程序 SynchronizationContext.SetSynchronizationContext
。你可以阅读更多关于 SynchronizationContext
在 这篇关于这个主题的MSDN文章。
默认的调度上下文应该是几乎所有时间都需要的,这意味着您不需要乱用它。我只在进行单元测试或Console程序/ Win32服务时更改它。
如何在等待昂贵的方法之前通过方法中途更改调度程序,然后再将其重新设置?
如果你想做一个昂贵的操作(大概是在线程池上),那么 await
的结果 TaskEx.Run
。
如果您想因其他原因(例如,并发)更改调度程序,那么 await
的结果 TaskFactory.StartNew
。
在这两种情况下,方法(或委托)都在另一个调度程序上运行,然后该方法的其余部分将在其常规上下文中继续。
理想情况下,你想要每一个 async
存在于单个执行上下文中的方法。如果方法的不同部分需要不同的上下文,则将它们拆分为不同的方法。这条规则的唯一例外是 ConfigureAwait(false)
,允许方法在任意上下文中启动,然后在其执行的剩余时间内恢复到线程池上下文。 ConfigureAwait(false)
应该被视为一种优化(默认情况下是库代码),而不是设计理念。
以下是我的“Thread is Dead”演讲中的一些观点,我认为可以帮助您完成设计:
我会小心翼翼地回答。 ;)
问题1:任何人都可以向我保证隐含的方法是个好主意吗?我看到ConfigureAwait引入了很多问题(false)以及传统/第三方代码中的显式调度。例如,我怎样才能确定我的'await-ridden'代码总是在UI线程上运行?
规则 ConfigureAwait(false)
非常简单:如果您的方法的其余部分可以在线程池上运行,则使用它,如果您的方法的其余部分必须在给定的上下文中运行(例如,UI上下文),则不要使用它。
一般来说, ConfigureAwait(false)
应该由库代码使用,而不是由UI层代码(包括UI类型层,如MVVM中的ViewModels)使用。如果该方法是部分后台计算和部分UI更新,则应将其拆分为两种方法。
问题2:因此,假设我们从代码中删除所有TaskScheduler DI并开始使用隐式调度,那么我们如何设置默认任务调度程序?
async
/await
通常不会使用 TaskScheduler
;他们使用“调度上下文”概念。这实际上是 SynchronizationContext.Current
,并回归 TaskScheduler.Current
只有没有 SynchronizationContext
。因此,可以使用替换您自己的调度程序 SynchronizationContext.SetSynchronizationContext
。你可以阅读更多关于 SynchronizationContext
在 这篇关于这个主题的MSDN文章。
默认的调度上下文应该是几乎所有时间都需要的,这意味着您不需要乱用它。我只在进行单元测试或Console程序/ Win32服务时更改它。
如何在等待昂贵的方法之前通过方法中途更改调度程序,然后再将其重新设置?
如果你想做一个昂贵的操作(大概是在线程池上),那么 await
的结果 TaskEx.Run
。
如果您想因其他原因(例如,并发)更改调度程序,那么 await
的结果 TaskFactory.StartNew
。
在这两种情况下,方法(或委托)都在另一个调度程序上运行,然后该方法的其余部分将在其常规上下文中继续。
理想情况下,你想要每一个 async
存在于单个执行上下文中的方法。如果方法的不同部分需要不同的上下文,则将它们拆分为不同的方法。这条规则的唯一例外是 ConfigureAwait(false)
,允许方法在任意上下文中启动,然后在其执行的剩余时间内恢复到线程池上下文。 ConfigureAwait(false)
应该被视为一种优化(默认情况下是库代码),而不是设计理念。
以下是我的“Thread is Dead”演讲中的一些观点,我认为可以帮助您完成设计: