众所周知,在Scala中使用Future需要声明执行上下文,该上下文创建一个线程池,该线程池用于运行Future中显示的代码。我的问题是,使用Future.successful或Future.failed是否将此请求跳过到线程池。性能影响对于正确使用Future至关重要。
为了提供一些背景知识,一位具有多年Scala经验的同事告诉我,不鼓励直接使用Future()包装一些代码块,因为有意义的是,Future调用中的代码必须具有引发异常的可能性,这是不可取的。在我们的代码库中,直接引发异常被认为是无法正常工作的样式,并且还具有性能影响,因为引发异常是相对较慢的操作,具有性能成本,因此应避免使用。我的问题分为两部分:
1)我想知道避免直接调用Future()是否还有其他潜在影响:使用Future.successful和Future.failed是否通过不在线程池中调度线程上的工作来节省计算资源?通过创建一个已经完成的Future,这两个编程结构是否避免从线程池中请求线程?
具体来说,让我们比较两个代码块:
a)
val fut = Future(1+1)
和
b)
val fut = Future.successful(1+1)
b)是否通过不去线程池来节省计算资源?
2)另外,我还想知道在映射或映射Future时是否从线程池中请求了线程。例如,我注意到任何涉及Future平面图的代码都需要定义执行上下文。这是否意味着flatmap操作本身是在线程池中的线程上调度的?是否会在线程池中的某个线程上发生Future上的每个映射或平面映射操作?在那种情况下,即使由于使用Future.successful和Future.failed而已经完成,只要我们正在映射或映射Future,是否必然要从线程池中请求线程?
具体来说,让我们看一个例子:
val fut = Future.successful(1+1).map(x => x+1)
映射操作是否发生在从执行上下文管理的线程池中请求的线程内部?
这只是让我更好地理解为什么使用Future.successful和Future.failed比使用Future()直接包装一些代码更好的样式。重复上面的内容,我已经知道抛出异常是性能瓶颈,但是使用Future.successful和Future.failed是否可以避免从线程池中完全请求线程,从而降低性能开销?这是否完全无关紧要,因为无论如何都必须在线程池中的线程上调度Future的映射或映射?
答案 0 :(得分:2)
Future.successful
和Future.failed
不需要执行上下文,因此它们不消耗线程。但是,在它们上调用map/flatMap/foreach
确实需要传入的回调具有执行上下文,因此确实消耗了线程。除了性能方面的考虑外,调用Future.successful(v)
而不是Future(v)
还可以从语义上表明我们已经拥有值v
,而只是将其提升为Future
。从Future.successful(1+1)
到Future(1+1)
的性能提升在实际系统中可能微不足道,在该系统中,真正的瓶颈将是缓慢的I / O,例如远程API调用,数据库查找等。