【问题标题】:Does use of Future.successful and Future.failed request a thread from the thread pool managed by the execution context使用 Future.successful 和 Future.failed 是否从执行上下文管理的线程池中请求一个线程
【发布时间】: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


    【解决方案1】:

    Future.successfulFuture.failed 不需要执行上下文,因此它们不消耗任何线程。但是在它们上调用map/flatMap/foreach 确实需要传入回调的执行上下文,因此确实消耗了一个线程。除了性能方面的考虑之外,调用Future.successful(v) 而不是Future(v) 更适合在语义上表明我们已经拥有v 的值,我们只是将其提升为Future。与Future(1+1) 相比,Future.successful(1+1) 的性能提升在实际系统中可能可以忽略不计,因为真正的瓶颈将是慢速 I/O,例如远程 API 调用、数据库查找等。

    【讨论】:

    • 除了性能考虑之外,.successful 应该只用于安全系统,因为Exception 在那里提出不会被捕获并表示为Future.failed
    猜你喜欢
    • 1970-01-01
    • 2018-07-19
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    • 2010-12-15
    • 2014-11-16
    • 2021-06-16
    • 2013-11-28
    相关资源
    最近更新 更多