我的Scala代码中出现奇怪的异步/多重现象

时间:2018-05-14 19:31:19

标签: scala

我的代码:

val byDate = data.groupBy(_._1).map(t => t._1 -> t._2.map(_._2).toMap).flatMap {
...
}


var incomplete: Option[LocalDate] = None
val filtered = (incomplete.map { i =>
  println(s"i = $i")

  byDate.filterKeys { d =>
    println(s"dd = $d vs i = $i")
  }
}).getOrElse(byDate)

如何理解(incomplete.map {})的作用?从输出,我猜它开始另一个线程?我对吗?因为,上述代码的输出被其他输出分开(在上述程序之后由某些代码打印出来)。

... other outputs generated by some codes after the above piece of codes ...
dd = 2018-05-11 vs i = 2018-05-12
dd = 2018-05-10 vs i = 2018-05-12
dd = 2018-05-13 vs i = 2018-05-12
dd = 2018-05-14 vs i = 2018-05-12
... other outputs generated by some codes after the above piece of codes ...
dd = 2018-05-10 vs i = 2018-05-12
dd = 2018-05-11 vs i = 2018-05-12

更新

我已经有一个原因:filterKeys does evaluation lazily,因此,只有在filtered使用后,它才会开始评估。

2 个答案:

答案 0 :(得分:1)

Scala集合上调用的操作(如map)是顺序执行还是并行执行,取决于集合的类型。

默认情况下导入的集合是顺序的,但只需在集合上调用par即可实现并行执行。

让我们举一个例子:

 (1 to 10).map { i => println(s"accessing sequentially $i") }

这会按预期提供以下顺序输出:

accessing sequentially 1
accessing sequentially 2
accessing sequentially 3
accessing sequentially 4
accessing sequentially 5
accessing sequentially 6
accessing sequentially 7
accessing sequentially 8
accessing sequentially 9
accessing sequentially 10

然而,我们可以使用par方法

来实现并行执行
 (1 to 10).par.map { i => println(s"accessing parallel $i") }

其中给出了以下输出:

accessing parallel 1
accessing parallel 2
accessing parallel 3
accessing parallel 4
accessing parallel 5
accessing parallel 8
accessing parallel 9
accessing parallel 10
accessing parallel 6
accessing parallel 7

我认为您看到混合输出语句的原因可能是,您的程序包含其他一些线程?

另一种可能性是,您的收藏品是并行类型。

您可以安全地删除您看到的parantheses,而无需更改程序的输出。

答案 1 :(得分:1)

  

括号可以在scala中启动一个新线程吗?

没有

  

如何理解(incomplete.map {})的作用?

与没有括号的incomplete.map {...}完全相同。括号完全是多余的。也许编写该代码的人认为括号需要在getOrElse之后调用map,但事实并非如此。 incomplete.map {...}.getOrElse(byDate)仍然是有效的语法,完全等效。

  

因为,上述代码的输出被其他输出分开(在上述程序之后由某些代码打印出来)。

无法确定为什么在没有看到其余代码(或至少是byDate的类型)的情况下发生这种情况是不可能的,但有一个合理的理论是byDate是比方说,一个流,其元素在迭代时进行评估。因此,如果byDate的定义包含print语句,则会在迭代byDate时执行这些语句。

另一个理论是你只是在其他地方启动多个线程。