【发布时间】:2019-11-07 20:10:06
【问题描述】:
众所周知,在 Scala 中使用 Future 需要声明一个执行上下文,它会创建一个线程池,用于运行出现在 Future 中的代码。我的问题是,如果使用 Future.successful 或 Future.failed 会将此请求跳过到线程池。性能影响对于正确使用 Future 很重要。
为了提供一些背景知识,一位具有多年 Scala 经验的同事告诉我,不鼓励直接使用 Future() 来包装一些代码块,因为为了有意义,Future 调用中的代码必须具有抛出异常的可能性,这是不可取的。在我们的代码库中,直接抛出异常被认为是非函数式的,并且还具有性能影响,因为抛出异常是一种相对较慢的操作,具有性能成本,因此应避免。我的问题有两个部分:
1) 我想知道避免直接调用 Future() 是否还有其他潜在影响:使用 Future.successful 和 Future.failed 是否通过不在线程池中调度线程上的工作来节省计算资源?通过创建一个已经完成的 Future,这两种编程结构是否避免了从线程池中请求线程?
具体来说,让我们比较两个代码块:
一)
val fut = Future(1+1)
和
b)
val fut = Future.successful(1+1)
b) 是否通过不进入线程池来节省计算资源?
2)另外,我也想知道在映射或平面映射Future时是否从线程池请求线程。例如,我注意到任何涉及 Future 上的平面图的代码都需要定义执行上下文。这是否意味着平面图操作本身被安排在线程池中的线程上? Future 上的每个 map 或 flatmap 操作是否都发生在线程池中的线程上?在那种情况下,只要我们正在映射或平面映射 Future,即使由于使用 Future.successful 和 Future.failed 而已经完成,是否不可避免地从线程池请求线程?
具体来说,让我们看一个例子:
val fut = Future.successful(1+1).map(x => x+1)
映射操作是否发生在从执行上下文管理的线程池中申请的线程内?
这只是为了让我更好地理解为什么使用 Future.successful 和 Future.failed 被认为比直接用 Future() 包装一些代码更好。重复我上面所说的,我已经知道抛出异常是一个性能瓶颈,但是使用 Future.successful 和 Future.failed 是否可以完全避免从线程池中请求线程,从而降低性能开销?这是否完全无关紧要,因为无论如何都必须在线程池中的线程上调度 Future 的映射或平面映射?
【问题讨论】:
标签: multithreading scala functional-programming threadpool future