加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 具有返回未来功能的遍历列表和流

发布时间:2020-12-16 09:42:17 所属栏目:安全 来源:网络整理
导读:介绍 Scala的未来(new in 2.10和now 2.9.3)是一个应用函数,这意味着如果我们有一个traversable type F,我们可以采用F [A]和函数A =未来[B]并将它们变成未来[F] [B]。 此操作在标准库中为 Future.traverse . Scalaz 7还提供了更常规的遍历,我们可以在此处
介绍

Scala的未来(new in 2.10和now 2.9.3)是一个应用函数,这意味着如果我们有一个traversable type F,我们可以采用F [A]和函数A =>未来[B]并将它们变成未来[F] [B]。

此操作在标准库中为Future.traverse. Scalaz 7还提供了更常规的遍历,我们可以在此处使用,如果我们从scalaz-contrib library导入Future的应用函数实例。

在流的情况下,这两个遍历方法的行为不同。标准库遍历在返回之前消耗流,而Scalaz的returns the future immediately:

import scala.concurrent._
import ExecutionContext.Implicits.global

// Hangs.
val standardRes = Future.traverse(Stream.from(1))(future(_))

// Returns immediately.
val scalazRes = Stream.from(1).traverse(future(_))

还有另一个区别,因为Leif Warner观察到here.标准库的遍历会立即启动所有异步操作,而Scalaz启动第一个,等待它完成,启动第二个,等待它等等。

流的不同行为

通过编写一个将在流中第一个值睡眠几秒钟的函数来显示此第二个差异是很容易的:

def howLong(i: Int) = if (i == 1) 10000 else 0

import scalaz._,Scalaz._
import scalaz.contrib.std._

def toFuture(i: Int)(implicit ec: ExecutionContext) = future {
  printf("Starting %d!n",i)
  Thread.sleep(howLong(i))
  printf("Done %d!n",i)
  i
}

Now.traverse(Stream(1,2))(toFuture)将打印如下内容:

Starting 1!
Starting 2!
Done 2!
Done 1!

和Scalaz版本(Stream(1,2).traverse(toFuture)):

Starting 1!
Done 1!
Starting 2!
Done 2!

这可能不是我们想要的。

和列表?

奇怪的是,两个遍历在这方面在列表上表现相同 – Scalaz不等待一个未来在开始下一个之前完成。

另一个未来

Scalaz还包括自己的concurrent套餐,自己实施期货。我们可以使用与上述相同的设置:

import scalaz.concurrent.{ Future => FutureZ,_ }

def toFutureZ(i: Int) = FutureZ {
  printf("Starting %d!n",i)
  i
}

然后我们得到Scalaz对列表和流的流的行为:

Starting 1!
Done 1!
Starting 2!
Done 2!

也许不太令人惊讶的是,遍历无限流仍然立即返回。

在这一点上,我们真的需要一个表来总结,但一个列表将要做:

>标准库遍历流;返回前消耗;不要等待每一个未来。
>流与Scalaz遍历:立即返回;等待每一个未来完成。
> Scalaz期货与流:立即回报;等待每一个未来完成。

和:

>标准库遍历列表:不要等待。
>列表与Scalaz遍历:不要等待。
>带有列表的Scalaz期货:等待每一个未来完成。

这是否有意义?列表和流上的此操作是否存在“正确”的行为?是否有一些原因,即“最不同步”的行为 – 即在返回之前不消耗收集,并且不要等待每一个未来的完成,然后继续下一步 – 在这里不代表?

解决方法

我无法回答这一切,但我尝试了一些部分:

Is there some reason that the “most asynchronous” behavior—i.e.,don’t
consume the collection before returning,and don’t wait for each
future to complete before moving on to the next—isn’t represented
here?

如果您有依赖计算和有限数量的线程,您可能会遇到死锁。例如,你有两个期货取决于第三个期货(全部三个在期货列表中),只有两个线程,你可以体验到前两个期货阻止所有两个线程,第三个未被执行的情况。 (当然,如果你的游泳池的大小是一个,也就是说,你可以相互执行一个计算,你可以得到类似的情况)

为了解决这个问题,你将来需要一个线程,没有任何限制。这适用于小型期货名单,但不适用于大型期货。所以如果你所有的并行运行,你会得到一个情况,小例子将在所有情况下运行,更大的一个将会死锁。 (示例:开发人员测试运行正常,生产死锁)。

Is there a “correct” behavior for this operation on lists and streams?

我认为这是不可能的期货。如果您更多地了解依赖关系,或者当您确定计算不会阻止时,可能会有更多并发解决方案。但是执行期货名单看起来是“破坏设计”。最好的解决方案似乎是一个,对于死锁的小例子(即,一个接一个地执行一个未来),这已经失败了。

Scalaz futures with lists: do wait for each future to complete.

我认为scalaz在内部使用理解进行遍历。对于理解,不能保证计算是独立的。所以我猜这个Scalaz在做正确的事情在这里与理解:做一个计算之后。在期货的情况下,这将始终有效,因为您在操作系统中拥有无限的线程。

所以换句话说:你只看到一个如何理解(必须)工作的神器。

我希望这是有道理的。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读