为什么我不能在Scala 3中加入包含for循环的线程?

yftpprvb  于 2023-04-21  发布在  Scala
关注(0)|答案(1)|浏览(143)

为什么只有这一个特定的代码打破时,其他一切工作?
在注解掉for循环或join()时没有问题。只是两者都不起作用。
使用while循环可以工作,将循环放在另一个类中也可以工作,在REPL中工作,或者作为脚本而不将其 Package 为对象/类(使用@main),在Scala 2中工作。不适用于同一个类/对象中的函数中的循环

object Main extends App {
  val t = new Thread() {
    override def run() = {
      println("Started")
      for (j <- 1 to 2) {println("Work")}
    }
  }
  t.start()
  t.join()
}

编辑:
我说的不起作用是指意外行为:同样用Thread.sleep(3000)替换join(),新线程(包含for循环)只有在主线程结束休眠后才继续执行(从for循环开始)
可以在Scastie中测试
迭代任何集合似乎都会导致这个问题。For可以被替换为这个块,但它仍然不会打印

it = List(1, 2, 3)
it.foreach(x => println(x))

但这会打印出来,这不应该工作,因为这是foreach的定义

it = List(1, 2, 3)
while(it.hasNext) println(it.next())
cwtwac6a

cwtwac6a1#

Scala 3 no longer treats DelayedInit the way Scala 2 did,结果App的主体现在作为静态初始化器的一部分执行(就像任何其他object一样)。除了加载类的线程之外的任何线程都将阻塞,直到静态初始化器完成为止(在这种情况下,静态初始化器甚至在App的合成main方法被调用之前就退出了)。
Seq(1, 2).foreach { _ => println("Working") }的情况下,{ _ => println("Working") }的主体被吊出成为部件(可能是一个方法,尽管我没有检查字节码),因此对foreach的调用被阻塞,直到Main在JVM眼中是一个“真实的的对象”,直到静态初始化器完成。不幸的是,静态初始化器(感谢join)正在等待foreach完成。while仍然由编译器进行特殊解释,并在字节码中变成循环。
这可以通过不扩展App而仅将对join的调用移动到main方法中(如this Scastie中)的最小更改来看出。(使Main成为JVM眼中的真实的对象,从而允许分叉线程中的foreach执行)。主方法被输入并且能够join分叉线程。

相关问题