0

这段代码是对其他有用的代码的简化。为了跟踪循环的进度,我在循环内累积一个 volatile var 计数,并使用 Java 并发的调度线程报告计数值。

def foo {
  import java.util.concurrent._
  @volatile var count = 0l
  val reportRunner = new Runnable { def run() = println(s"report=$count") }
  val scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
  val reportRunnerHandle = scheduledExecutorService.scheduleAtFixedRate(reportRunner, 0,1000,TimeUnit.MILLISECONDS)

  val l = Stream.fill(100000000)(0)
  println(s"start count=$count")

  for(i <- 0 until l.size) {
    count = count + 1
  }

  println(s"end count=$count")

  reportRunnerHandle.cancel(true)
  scheduledExecutorService.shutdown()
}

它为我产生了以下输出:

report=0
start count=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=0
report=60019827
end count=100000000

假设每个报告打印每秒发生一次,但它们会以突发形式发生并且在发生时具有相同的计数。感觉这里缺少一些基本的 JVM 并发问题。或者除了 ScheduledExecutorService 之外,也许还有更可靠的方法可以做到这一点?

这里也没有显示,但我已经尝试使用 AtomicLong 并使用 Actors 来累积计数而不是 volatile 的相同代码,但我得到了相同的结果,这让我怀疑 ScheduledExecutorService。

4

1 回答 1

1

你正在用你的循环做一些非常奇怪的事情。几乎所有时间都在l.size调用中,因为那是创建流的时间(你需要一个完全创建的流来知道它的大小)。然后循环本身将非常快地通过,而根本不引用流,因为它知道上限。而且您可能会因分配如此多的内存而遇到各种垃圾收集问题(特别是,GC 可能每次都必须遍历整个流,并且您可能正在使用 stop-the-world 收集器)。

尝试类似的东西

@volatile var count = 0L
var accum = 0.0
for (i <- 0 until 1000000000) {
  accum += math.tan(i)
  count += 1
}

获得一个以稳定(但不是非常快)的速度进行的循环。

于 2013-07-16T21:51:32.197 回答