在 Scala 中使用期货时,默认行为是使用默认的 Implicits.global 执行上下文。似乎这默认为每个处理器提供一个线程。在更传统的线程化 Web 应用程序中,当期货正在执行诸如等待数据库之类的任务(与某些 cpu 绑定任务相反)时,这似乎是一个糟糕的默认值。
我希望覆盖默认上下文在生产中是相当标准的,但我找不到关于这样做的文档很少,似乎它可能并不常见。我错过了什么吗?
在 Scala 中使用期货时,默认行为是使用默认的 Implicits.global 执行上下文。似乎这默认为每个处理器提供一个线程。在更传统的线程化 Web 应用程序中,当期货正在执行诸如等待数据库之类的任务(与某些 cpu 绑定任务相反)时,这似乎是一个糟糕的默认值。
我希望覆盖默认上下文在生产中是相当标准的,但我找不到关于这样做的文档很少,似乎它可能并不常见。我错过了什么吗?
与其将其视为覆盖默认执行上下文,不如问“我应该为不同的事情使用多个执行上下文吗?” 如果这是问题,那么我的答案是肯定的。在我工作的地方,我们使用 Akka。在我们的应用程序中,我们使用默认的 Akka 执行上下文来实现非阻塞功能。然后,由于目前没有好的非阻塞 jdbc 驱动程序,我们所有的阻塞 SQL 调用都使用单独的执行上下文,其中每个连接方法都有一个线程。保持主执行上下文(一个分叉连接池)不受阻塞会导致我们的吞吐量显着增加。
我认为在系统中为不同类型的工作使用多个不同的执行上下文是完全可以的。这对我们来说效果很好。
“正确”的答案是您需要使用 ExecutionContext 的方法在其签名中需要 ExecutionContext,因此您可以从“外部”提供 ExecutionContext(s) 以控制更高级别的执行。
是的,在您的应用程序中创建和使用其他执行上下文绝对是一个好主意。
执行上下文将模块化您的并发模型并隔离应用程序的不同部分,因此如果您的应用程序的一部分出现问题,其他部分将受到较小的影响。考虑您的示例,对于特定于 DB 的操作,您将有一个不同的执行上下文,而另一个用于处理 Web 请求的执行上下文。
在Jonas Boner 的演讲中,这种模式被称为在您的应用程序中创建“隔板”,以提高稳定性和容错性。
我必须承认,我对执行上下文使用本身的了解不多。但是,我确实看到在某些框架中应用了这个原则。例如,Play 将为不同类型的作业使用不同的执行上下文,并且它们鼓励您在必要时将任务拆分到不同的池中:Play Thread Pools
Akka 中间件还建议将您的应用程序拆分为应用程序中不同并发区域的不同上下文。他们使用Dispatcher的概念,它是电池的执行上下文。
此外,scala 并发库中的大多数运算符都需要执行上下文。这是设计使您在以并发方式模块化应用程序时为您提供所需的灵活性。