C#的Task
有ConfigureAwait(false)
个库,以防止与(例如)UI线程同步,这并不总是必要的:
http://msdn.microsoft.com/en-us/magazine/hh456402.aspx
在.NET中我相信只能有一个SynchonizationContext
,所以很清楚Task
应该在哪个线程池执行它的继续。
对于库,当你无法假设用户处于webrequest(在.NET HttpContext.Current.Items
流程中),命令行(普通多线程),XAML / Windows Forms(单个UI线程)时,使用它几乎总是更好ConfigureAwait(false)
,所以Waiter知道它可以只是在用于调用Waiter的任何线程上执行continuation(如果你在库中阻塞代码可能导致线程池上的线程饥饿,这只会很糟糕初始工作量开始,假设我们不这样做。)
关键是从库的角度来看,你不想使用来自调用者的线程池的线程来同步一个延续,你只需要继续在任何线程上运行。这样可以保存上下文切换并保持UI线程的负载。
在Scala中,对于期货的每个操作(即地图),您需要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
}
}
}
我正在使用游戏,我通常导入游戏的默认隐式ExecutionContext
。
block
上的映射需要在执行上下文中运行。
如果我在库中编写这段Scala,我会添加隐式参数executionContext
:
def trace[T](message: => String)(block: => Future[T])(implicit executionContext: ExecutionContext): Future[T] = {
而不是在图书馆中导入播放的默认ExecutionContext
。