我选择List[Int]
并想要并行查找值x
x * 10 > 500
。因此,如果列表包含51或更高的任何值,exists
应返回true
。
def f(x: Int) = {
println("calculating for " + x)
Thread.sleep(100 - x)
println("finished " + x)
x * 10
}
val res = List.range(1, 100).par.exists(f(_) > 500)
结果如下:
calculating for 1
calculating for 25
calculating for 50
calculating for 75
calculating for 13
finished 75 // <-- first valid result found: 75 * 10 > 500
finished 50
calculating for 51 // but it kicks off more expensive calculations
finished 25
calculating for 26
finished 13
calculating for 14
finished 1
calculating for 2
finished 51
finished 26
calculating for 27 // and more
finished 14
calculating for 15
finished 2
calculating for 3
finished 27
calculating for 28
finished 15
calculating for 16
finished 3
calculating for 4 // and more...
finished 28
calculating for 29
finished 16
calculating for 17
finished 29
calculating for 30
finished 4
calculating for 5
finished 17
calculating for 18
finished 30
finished 5
calculating for 6
finished 18
finished 6
res: Boolean = true
我正在使用带有Scala 2.9.1的双核机器。
这里发生了什么?这是否按预期工作?为什么不在发现第一个结果后立即将消息发送给其他线程以中止任务?如果f
是一项昂贵的计算,这可能会非常昂贵。
find
似乎以类似的方式工作,搜索更多的值,即使文档说“元素可能不一定是迭代顺序中的第一个这样的元素”和“选择是不确定的”
答案 0 :(得分:2)
为什么不将消息发送给其他线程以中止 一旦找到第一个结果,就会立即执行任务?
因为那是不可能的。 JAVA不会让你这么做。或者更确切地说,它已被弃用。
请参阅(已弃用)Thread.stop()
的说明:
这种方法本质上是不安全的。使用Thread.stop停止一个线程 使它解锁它锁定的所有监视器(作为 未经检查的ThreadDeath异常传播的自然结果 堆栈)。如果以前受这些对象保护的任何对象 监视器处于不一致状态,受损物体变为 其他线程可见,可能导致任意行为。 停止的许多用法应该由仅修改一些的代码替换 变量,表示目标线程应该停止运行。该 目标线程应定期检查此变量,并从中返回 如果变量指示它,则以有序的方式运行它的方法 是停止运行。如果目标线程等待很长时间(在a 例如,条件变量,应该使用中断方法 打断等待。有关详细信息,请参阅Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?。
换句话说,因为带锁的多线程代码本身就被破坏了,所以他们不赞成使用一个非常精细的方法,可以很好地与不共享可变状态的线程一起使用,因此不需要锁定数据结构。
答案 1 :(得分:1)
我理解这种愿望,因为我认为自己有这样的行为会很好 - 从使用快速退出代码的意图来看,它看起来是合理的,但当然,它应该如何实现呢?
在快捷键表达式中,如果找到结果,则不会启动下一个调用 - 这很容易。
但是你如何在一个已经完成的任务后面运行,并再次抓住它来阻止它?您需要知道哪些已经完成,并且可能会进入竞争状态,因为在测试时,无论它是否仍在运行,它可能会返回“true”,但之后会立即完成。
在exists
内部调用的函数本身可以启动新的线程 - 它们应该如何以一般方式从外部停止?通过提供可选的stop execution
- 方法作为第二个参数?