2013-05-30 33 views
26

在scala中使用futures时,默认行为是使用默认Implicits.global执行上下文。看来这默认为每个处理器提供一个线程。在更传统的线程Web应用程序中,当期货执行诸如等待数据库的任务(而不是某些cpu绑定任务)时,这似乎是一个糟糕的默认值。我应该重写默认的ExecutionContext吗?

我期望重写默认的上下文在生产中是相当标准的,但是我可以找到关于这么做的很少的文档,看起来它可能并不常见。我错过了什么吗?

回答

39

而不是将其视为重写默认执行上下文,为什么不问问“我应该为不同的事情使用多个执行上下文?”如果这是问题,那么我的答案是肯定的。我在哪里工作,我们使用阿卡。在我们的应用程序中,我们使用默认的Akka执行上下文来实现非阻塞功能。然后,因为当前没有好的非阻塞jdbc驱动程序,我们所有的阻塞SQL调用都使用单独的执行上下文,我们在每个连接方法中都有一个线程。保持主执行上下文(分支连接池)不受阻塞导致我们的吞吐量显着增加。

我认为完全可以在系统中为不同类型的工作使用多个不同的执行上下文。它对我们很好。

+3

+1提到重要的决定因素是您是否在期货中使用阻塞(或长期运行)代码。如果你不这样做,使用单独的执行上下文实际上是反生产的。 –

+0

如果你想要一个自定义的执行器,你可以控制,但想坚持默认的并行机制和其他参数,似乎'ExecutionContext.fromExecutor(new scala.concurrent.forkjoin.ForkJoinPool)'(不带参数)似乎做的伎俩;在我的i7上创建了一个包含8个核心(包括超线程)的8个池,它与'ForkJoinPool'匹配。commonPool'包含。 –

+0

@cmbaxter你是否将你的JDBC调用封装在期货的'blocking {}中?如果有独立的ExecutionContext,是否有必要? –

2

是的,在您的应用程序中创建和使用其他执行上下文绝对是一个好主意。

执行上下文将模块化您的并发模型并隔离应用程序的不同部分,以便在应用程序的某个部分出现问题时,其他部分受此影响较小。考虑你的例子,你将有不同的执行上下文用于特定于数据库的操作,另一个用于处理Web请求。

在Jonas Boner的this presentation中这种模式被称为在您的应用程序中创建“Bulkheads”以获得更高的稳定性&容错。

我必须承认,我自己并没有听说过有关执行上下文的用法。但是,我确实看到这个原则适用于某些框架。例如,Play将针对不同类型的作业使用不同的执行上下文,并鼓励您根据需要将您的任务分成不同的池:Play Thread Pools

Akka中间件还建议将您的应用程序分割为不同并发区域的不同上下文你的申请。他们使用Dispatcher的概念,这是电池的执行环境。

此外,scala并发库中的大多数运算符都需要执行上下文。这在设计上为您提供了在模块化应用程序并发性时所需的灵活性。

+1

Scala中的默认'ExecutionContext'是最新的ForkJoin池。鉴于此,您的陈述表明全球执行环境“适用于小型快速工作,但肯定不会扩展到更大的应用程序”是没有根据的。 –

+0

这并不是说默认的执行上下文本身并不是高性能的。我的意思是说,在大规模应用程序中只使用一个执行上下文不是最好的。尽管如此,由于混乱,我删除了该评论。 –

3

“正确的”答案是您的需要使用ExecutionContext的方法需要在其签名中使用ExecutionContext,因此您可以从“外部”提供ExecutionContext以控制更高级别的执行。

相关问题