所以对于家庭作业,我应该使用几个线程机制,使用一个简单的函数集成,应该产生pi。该实施应该处理超过5000亿的间隔。我当前的实现在 2GB 的堆大小上处理多达大约 5000 万个 for 循环。现在我的问题是为什么实现使用这么多内存?(我认为这是因为范围必须提前确定,这是真的吗?如何提高内存使用率?是否可以使用并行集合,或者我是否被迫使用线程池进行此类操作?
注意:我将通过以下实现获得全部荣誉。这是为了我的求知欲和我对斯卡拉语更流利的梦想。
import scala.Math
object Pi {
def calculate_pi(interval: Int): Double = {
val start: Long = System.currentTimeMillis;
var duration: Long = 0
var x: Double = 2.0/interval
var y: Double = 0.0
var mypi: Double = 0.0
(x until 1.0 by 1.0/interval).par.foreach(i => {
y = 4.0/(1.0+x*x)
mypi += (1.0/interval)*y
})
duration = (System.currentTimeMillis - start)
println("scala calculate_pit" + interval + "t" + duration + "mst" + mypi)
return mypi
}
object Main extends App {
println("Please input the interval for the calculation")
if(args.length < 1) { sys.exit }
val interval = args(0).toInt
Pi.calculate_pi_seq(interval)
Pi.calculate_pi(interval)
}
这是各种错误:
(x until 1.0 by 1.0/interval).par.foreach(i => {
y = 4.0/(1.0+x*x)
mypi += (1.0/interval)*y
})
第一个问题是y
的所有计算都是相同的:你在计算时没有使用i
。由于x
不会更改,因此所有线程都计算相同的值。
这是第二个问题,您正在并行计算mypi
(和y
(。这意味着多个线程同时读取和写入mypi
和y
。
让我们考虑一个执行来理解其中的问题。假设第一个线程开始运行,计算y
,然后读取y
和mypi
。然后,该线程暂停,所有其他线程运行。最后,该线程恢复并将其计算结果写入mypi
。在这种情况下,所有其他线程的所有计算都将被浪费,因为最终值是由该线程给出的。
这是一个简单的案例。基本上,你根本无法预测每个读取和写入mypi
会发生什么(y
更容易,因为所有线程都为其分配相同的值(。
而且,是的,当您在NumericRange
上调用.par
时,它会创建一个包含该NumericRange
的所有值的集合。
由于不知道底层应用程序,我通过实验了解到,如果您使用该方法par
Range
(例如(,它会提前实例化,正如您所指出的。
但是,看起来您只是使用集合来利用并行化。换句话说,计算一段与集合本身无关的代码 - 甚至没有使用i
的值。因此,foreach 循环几乎是多余的,因为您只对 y 和 x 值感兴趣。对于一个简单的 for 循环可以完成的事情来说,这似乎是大量的工作。
也就是说,其他类型的并行化在scala中非常容易。使用演员呢?它们重量轻且非常简单。否则,工作线程甚至 Java 线程可能会解决问题。