C# 的Task
库ConfigureAwait(false)
可以防止与(例如)UI 线程同步,这并不总是必要的:http:
//msdn.microsoft.com/en-us/magazine/hh456402.aspx
在 .NET 中,我相信只能有一个SynchonizationContext
,因此很清楚Task
应该在哪个线程池上继续执行它。
对于库,当您不能假设用户在 webrequest(在 .NETHttpContext.Current.Items
流中)、命令行(普通多线程)、XAML/Windows 窗体(单个 UI 线程)中时,使用它几乎总是更好ConfigureAwait(false)
,所以服务员知道它可以只在用于调用 Waiter 的任何线程上执行延续(如果您在库中执行阻塞代码,这可能会导致启动初始工作负载的线程池上的线程饥饿,这只是不好的,假设我们不这样做'不要那样做)。
关键是从库的角度来看,您不想使用调用者线程池中的线程来同步延续,您只希望延续在任何线程上运行。例如,这节省了上下文切换并保持 UI 线程的负载。
在 Scala 中,对于 Futures 上的每个操作(即映射),您需要一个ExecutionContext
(隐式传递)。这使得管理线程池非常容易,我更喜欢 .NET 有点奇怪TaskFactory
的方式(似乎没有人使用,他们只使用默认值TaskFactory
)。
我的问题是,Scala 是否存在与 .NET 相同的问题,即有时不必要的上下文切换,如果是这样,是否有类似于 的方法ConfigureAwait
来解决此问题?
我在 Scala 中找到的具体示例,我对此感到疑惑:
def trace[T](message: => String)(block: => Future[T]): Future[T] = {
if (!logger.isTraceEnabled) block
else {
val startedAt = System.currentTimeMillis()
block.map { result =>
val timeTaken = System.currentTimeMillis() - startedAt
logger.trace(s"$message took ${timeTaken}ms")
result
}
}
}
我正在使用 play 并且我通常会导入 play 的默认值,implicit ExecutionContext
。上的地图block
需要在执行上下文中运行。
如果我在库中编写这段 Scala 并添加一个隐式参数executionContext
:
def trace[T](message: => String)(block: => Future[T])(implicit executionContext: ExecutionContext): Future[T] = {
而不是在库中导入 play 的默认值ExecutionContext
。