Scala 中多个 Future 的奇怪情况

发布于 2024-11-14 02:58:59 字数 516 浏览 3 评论 0原文

Scala 中那些与 Future 相关的类和特征之间有什么联系?为什么它们分布在不同的包中?

我发现了这些:

abstract class scala.actors.Future
object         scala.actors.Futures
trait/object   scala.collection.parallel.FutureThreadPoolTasks
trait          scala.concurrent.FutureTaskRunner
trait          scala.parallel.Future    (the package consists of only this file...)

它们是否有显着不同的事情,或者是否有其他原因导致它们无法合并?

有没有一个很好的例子来说明何时使用其中一种或另一种?

编辑:奖励解释每个类/特征/对象的作用以及它们如何证明其存在的合理性/它们如何有用。

What's the the connection between those Future-related class and traits in Scala, and why are they sprinkled over different packages?

I have found those:

abstract class scala.actors.Future
object         scala.actors.Futures
trait/object   scala.collection.parallel.FutureThreadPoolTasks
trait          scala.concurrent.FutureTaskRunner
trait          scala.parallel.Future    (the package consists of only this file...)

Do they significantly different things or is there another reason why they can't be consolidated?

Is there a good example showing when one would use the one thing or the other?

Edit: Bounty for explaining what each of the classes/traits/objects does and how they justify their existance/how they are useful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妥活 2024-11-21 02:58:59

scala.actors._

abstract class Future

首先,让我们看看文档是怎么说的:

arity 0 的函数,返回 T 类型的值,应用该值时,会阻止当前参与者 (Actor.self),直到未来的值可用为止。

这基本上就是全部了。如果您从另一个 Actor 之外的任何地方与 Actor 进行通信(它可以使用 sender 引用简单地通过另一条消息接收对消息的异步回复)并且您需要对已发送消息的回复,那么您可以有两种选择:

  • 发送一条阻塞消息,等待 Actor 完成计算结果
  • 使用返回 Future 的方法发送一条消息,并且仅当您确实需要相关值时才阻塞该 Future(到那时该值可能已经被 因此,

Future 是一个尚未存在但可能在不久的将来会存在的值的占位符。下面的内容也很有趣:

可以在不阻塞的情况下查询 future 以查明其值是否已经可用 [使用“isSet”]。

这允许您做任何您想做的事情,直到计算/获取您需要的值,并且您可以定期检查该值是否可用。

当深入研究 Scala 库源代码时,我发现 Futures 实际上只是参与者。 Future本身是一个抽象类,由私有类FutureActor扩展。最后一个类是实际实现 Future 功能的类。

object Futures

到目前为止,object Futures 并不那么有趣,因为它仅仅是“操作 futures 的方法”的容器,方便的工厂方法 future 异步评估传递的块,返回代表结果的 future。一个小例子是这样的:

import scala.actors.Futures
val f = Futures.future {
    println("Start: inside block")
    val s = System.currentTimeMillis
    while(System.currentTimeMillis < (s + 1000)) {
        // Simulate computation
    }
    println("Start: end of block")
    42
}
println("After future")
println(f())
println("The end")

这应该会导致类似的结果

Start: inside block
After future
Start: end of block
42
The end

这表明 future 调用不会阻止以下代码,直到您实际尝试检索 future 的值(请注意,输出是非确定性也可能出现在开头。输出)。

scala.collection.parallel

这个包是 Scala 2.9.x 中的新包,它为我们最喜​​欢的一些集合实现了并行对应项。这些都以 Par 开头:

  • ParIterable
  • ParSeq
  • ParSet
  • ParMap

您可能已经知道或猜到,这些集合以并行方式实现所有可能的操作,而您无需担心。一个小演示:

(1 to 10).par.map { b => print(b + " "); b * b }
3 1 6 2 7 4 5 9 10 8
    # => (1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

结果始终是相同的,但处理元素的顺序又是不确定的。此外,如果您使用的是多核系统,对于较大的集合,您可能会体验到良好的性能提升。

trait FutureThreadPoolTask​​s

FutureThreadPoolTask​​s 特征扩展了 Tasks 特征,所以让我们先看一下这个特征。该特征上方的评论说:

声明并行集合使用的任务执行功能的特征。

从其他源注释和 Tasks 特征中找到的方法来看,任务表示需要计算的工作单元。根据问题是否可以进一步划分,以及如果有更多可用资源,任务可以通过创建更多任务来进一步拆分任务。

现在,FutureThreadPoolTask​​s 特性本身只是一种计算任务的方法,它使用 java.util.concurrent.Future 类进行同步,也就是说,它确实不要使用scala.actors.Future!从源头看:

基于 Java 线程池 API 和使用 future 进行同步的任务对象实现。

object FutureThreadPoolTask​​s

再次不是很引人注目,只是一个伴随对象,其中包含 FutureThreadPoolTask​​s 特征使用的一些(实际上只有三个)实用程序方法。

scala.concurrent

关于这些类的文档非常糟糕,而且显然很少有(我没有找到一个)示例来演示这些类的用法。我一定会尽力收集更多有关这些的信息,并尽快扩展本节!

scala.parallel

trait Future

这似乎是一个“正在进行中的工作”,因为 scala.parallel 包仅包含此特征。据我所知,这将与不使用 ActorsFuture 实现相关,但这只是一个猜测。该特征的签名如下,

trait Future[@specialized +R] extends (() => R)

我什至不打算尝试解释 @specialized 注释变体(通用 R 类型之前的 +),但这个特征的基本思想是,Future 是一个函数,在执行时返回值(如果尚未计算,则必须阻塞)。

此外,特征本身内部只有两个方法,applyisDone。我的猜测是,isDone 就像 scala.actors.Future.isSet 一样,应该是一个非阻塞调用,以查看值是否已计算出来,并且应该使用 apply 方法来实际检索该值。

scala.actors._

abstract class Future

First of all, lets see what the documentation says:

A function of arity 0, returing a value of type T that, when applied, blocks the current actor (Actor.self) until the future's value is available.

And that is basically all there is. If you are communicating with an Actor from anywhere outside of another actor (which can receive asynchronous replies to messages simply with another message, using the sender reference) and you need the reply to a sent message, you have two choices:

  • Send a blocking message which waits until the Actor is done computing your result
  • Send a message using a method which returns a Future, and block on that Future only if you really need the value in question (which by then may have alreay been computed)

So a Future is a placeholer for a value which does not yet exist, but probably will in the near future. The following is also interesting:

A future can be queried to find out whether its value is already available without blocking [using "isSet"].

This allows you to do whatever you want until the value you need has been computed/fetched, and you can periodically check if the value has become available.

When digging a bit into the Scala library source code, I found out that Futures are actually just actors. Future itself is a an abstract class, which is extended by the private class FutureActor. This last class is the one that actually implements the Future-functionality.

object Futures

The object Futures is by far not as interesting, as it is merely a container for the "Methods that operate on futures", the handy factory method future which asynchronously evaluates the passed block, returning a future representing the result. A small example would be this:

import scala.actors.Futures
val f = Futures.future {
    println("Start: inside block")
    val s = System.currentTimeMillis
    while(System.currentTimeMillis < (s + 1000)) {
        // Simulate computation
    }
    println("Start: end of block")
    42
}
println("After future")
println(f())
println("The end")

Which should result in something like

Start: inside block
After future
Start: end of block
42
The end

This demonstrates that the future-call does not block the following code until you actually try to retrieve the value of the future (note that the output is non-deterministic. After future could also appear at the beginning of the output).

scala.collection.parallel

This packages is new to Scala 2.9.x and implements parallel counterparts for some of our favorite collections. These all start with Par:

  • ParIterable
  • ParSeq
  • ParSet
  • ParMap

As you may have known or guessed already, these collections implement all possible operations in a parallel manner without you having to worry about it. A small demonstration:

(1 to 10).par.map { b => print(b + " "); b * b }
3 1 6 2 7 4 5 9 10 8
    # => (1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

The result will always be the same, but the order in which the elements are processed is again non-deterministic. Also, if you are on a multicore system, you will probably experience a nice performance boost for larger collections.

trait FutureThreadPoolTasks

The FutureThreadPoolTasks trait extends the Tasks trait, so lets take a look at that one first. The comment above the trait says:

A trait that declares task execution capabilities used by parallel collections.

Judging from the other source comments and the methods found in the Tasks trait, a Task represents a unit of work which needs to be computed. Depending on wether or not a problem is divisible further and if there are more resources available, a Task can split up a Task further by creating more tasks.

Now the FutureThreadPoolTasks trait itself is just a way to compute tasks, which uses the java.util.concurrent.Future class for its synchronization, that is, it does not use scala.actors.Future! From the source:

An implementation of tasks objects based on the Java thread pooling API and synchronization using futures.

object FutureThreadPoolTasks

Once again not very spectacular, just a companion object containing a few (actually only three) utility methods which the FutureThreadPoolTasks trait uses.

scala.concurrent

The documentation on these classes is really bad and apparently there are very few if any (I didn't find a single one) examples which demonstrate the usage of these classes. I will definitely try to gather more information on these and expand on this section as soon as I can!

scala.parallel

trait Future

This seems to be a "Work in progess", as the scala.parallel package only contains this trait. From what I can tell, this is going to be related to a Future implementation which does not use Actors, but that is just a guess. The signature of the trait is the following

trait Future[@specialized +R] extends (() => R)

I am not even going to try to explain the @specialized annotation or variances (the + before the generic R type), but the basic idea in this trait is that a Future is a function which, when executed, returns the value (and must therefor block if it has not been computed yet).

Also, there are only two methods inside the trait itself, apply and isDone. My guess is that isDone, just like the scala.actors.Future.isSet, is supposed to be a non-blocking call to see if the value has been computed, and the apply method should be used to actually retrieve the value.

漫雪独思 2024-11-21 02:58:59

下面是一个简单的解释。 (部分内容是从 scala 文档复制的)。如果您有不明白的地方,请告诉我,我会尽力更具体,并给您一个具体的例子。

抽象类scala.actors.Future -- 你熟悉java.util.concorrent.Futurescala.actors.Future 基本上表示异步计算的结果,但对于 actors 来说。

scala.actors.Futures -- 一个对象 (~singleton),包含四个用于处理 scala.actors.Future 的实用方法。

scala.parallel.Future --(这对我来说是新的,但它包含非常基本的操作(apply 和 isDone))它是一个没有参数的函数,如果与以下内容相关的并行计算将阻止调用者功能未完成。 (函数?提示:extends())

scala .collection.parallel.FutureThreadPoolTask​​s -- 来自 scala 文档:“基于 Java 线程池 API 和使用 future 进行同步的任务对象的实现。”够了吗? :)

scala.concurrent.FutureTaskRunner -- 你熟悉执行器ExecutorScheduler 是 scala 标准库中的一个(三分之一)具体实现。 executeFromActor 是更有趣的方法之一,应该会提示您何时需要使用此方法

Below is a brief explanation. (Parts are copied from the scala doc). Let me know if there is something that you dont understand and I will try to be more specific and give you a concrete example.

abstract class scala.actors.Future -- Are you familiar with java.util.concorrent.Future? scala.actors.Future basically represents the result of an asynchronous computation but for actors.

scala.actors.Futures -- An object (~singleton) that contains four utility methods for handling scala.actors.Future.

scala.parallel.Future -- (This one was new to me, but it contains very basic operations (apply and isDone)) its a function without parameters that will block the caller if the parallel computation associated with the function is not completed. (function? hint: extends () )

scala.collection.parallel.FutureThreadPoolTasks -- From the scala doc: "An implementation of tasks objects based on the Java thread pooling API and synchronization using futures." Is that enough? :)

scala.concurrent.FutureTaskRunner -- Are you familiar with Executor? ExecutorScheduler is one (out of three) concrete implementations in the scala standard library. executeFromActor is one of the more interesting methods and should give you a hint about when you need to use this one

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文