Я в восторге от того, что этот фрагмент кода использует все мои процессоры, чтобы быстрее найти (правильный) ответ, но ... почему он это делает? - PullRequest
3 голосов
/ 27 сентября 2011

Таким образом, я возился с некоторыми простыми проблемами, чтобы стать лучше в scala, и я написал следующую программу для вычисления простых чисел, используя сито Эратосфена.Когда я увеличил число простых чисел, чтобы найти, я заметил, что мой процессор будет максимальным во время расчета.Теперь я понятия не имею, почему он использует более 1 ядра, и я боялся, что это испортит ответ, но он выглядит правильным при нескольких запусках, поэтому это не должно быть.Я нигде не использую .par, и большая часть всей моей логики находится в недоумении.

Редактировать: я использую scala 2.9.1

object Main {
  val MAX_PRIME = 10000000

  def main(args: Array[String]) {
    println("Generating array")
    val primeChecks = scala.collection.mutable.ArrayBuffer.fill(MAX_PRIME + 1)(true)
    primeChecks(0) = false

    println("Finding primes")
    for (
      i ← 2 to MAX_PRIME if primeChecks(i);
      j ← i * 2 to MAX_PRIME by i
    ) primeChecks(j) = false

    println("Filtering primes")
    val primes = for { (status, num) ← primeChecks.zipWithIndex if status } yield num

    println("Found %d prime numbers!".format(primes.length))

    println("Saving the primes")
    val formatter = new java.util.Formatter("primes.txt", "UTF-8")
    try {
      for (prime ← primes)
        formatter.format("%d%n", prime.asInstanceOf[Object])
    }
    finally {
      try { formatter.close } catch { case _ ⇒ }
    }
  }
}

Редактировать 2: Вы можетеиспользуйте следующий фрагмент в REPL, чтобы получить многопоточное поведение, поэтому оно должно быть из-за простоты понимания (по крайней мере, в scala 2.9.1).

val max = 10000000
val t = scala.collection.mutable.ArrayBuffer.fill(max + 1)(true)
for (
    i <- 2 to max if t(i);
    j <- i * 2 to max by i
) t(j) = false

Ответы [ 2 ]

4 голосов
/ 27 сентября 2011

Это не ваш код, который использует несколько потоков, а JVM. Вы видите, как включается GC. Если я увеличу MAX_PRIME до 1000000000 и предоставлю ему 6 ГБ стека Java для игры, я смогу увидеть устойчивое состояние 100% 1 ЦП и около 4 ГБ памяти. Время от времени включается GC и затем он использует 2 процессора. Следующая трассировка стека Java (сокращена для ясности) показывает, что работает внутри JVM:

"Attach Listener" daemon prio=3 tid=0x0000000000d13800 nid=0xf waiting on condition [0x0000000000000000]
"Low Memory Detector" daemon prio=3 tid=0x0000000000a15000 nid=0xd runnable [0x0000000000000000]
"C2 CompilerThread1" daemon prio=3 tid=0x0000000000a11800 nid=0xc waiting on condition [0x0000000000000000]
"C2 CompilerThread0" daemon prio=3 tid=0x0000000000a0e800 nid=0xb waiting on condition [0x0000000000000000]
"Signal Dispatcher" daemon prio=3 tid=0x0000000000a0d000 nid=0xa runnable [0x0000000000000000]
"Finalizer" daemon prio=3 tid=0x00000000009e7000 nid=0x9 in Object.wait() [0xffffdd7fff6dd000]
"Reference Handler" daemon prio=3 tid=0x00000000009e5800 nid=0x8 in Object.wait() [0xffffdd7fff7de000]
"main" prio=3 tid=0x0000000000428800 nid=0x2 runnable [0xffffdd7fffa3d000]
   java.lang.Thread.State: RUNNABLE
    at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:76)
"VM Thread" prio=3 tid=0x00000000009df800 nid=0x7 runnable 
"GC task thread#0 (ParallelGC)" prio=3 tid=0x0000000000438800 nid=0x3 runnable 
"GC task thread#1 (ParallelGC)" prio=3 tid=0x000000000043c000 nid=0x4 runnable 
"GC task thread#2 (ParallelGC)" prio=3 tid=0x000000000043d800 nid=0x5 runnable 
"GC task thread#3 (ParallelGC)" prio=3 tid=0x000000000043f800 nid=0x6 runnable 
"VM Periodic Task Thread" prio=3 tid=0x0000000000a2f800 nid=0xe waiting on condition

Существует только один (основной) поток, выполняющий код Scala, все остальные - внутренние JVM. Обратите внимание, в частности, в этом случае 4 потока GC - это потому, что я запускаю это на 4-сторонней машине, и по умолчанию JVM выделит 1 поток GC на ядро ​​- точная настройка будет зависеть от конкретной комбинации платформы, JVM и флаги командной строки, которые используются.

Если вы хотите понять детали (это сложно!), Вам следует начать со следующих ссылок:

0 голосов
/ 27 сентября 2011

Обновление: Дальнейшее тестирование с помощью предоставленного jar приводит к многоядерному использованию на OSX, Java 1.6.0_26, виртуальной машине сервера HotSpot, Scala 2.9.1.

Если вы используете *Система, основанная на nix, скажет 90% и будет использовать только одно ядро.Он скажет 230% для 100% 2 ядер и 30% другого или любого другого варианта.

Для этого кода на моей машине загрузка ЦП отскокает между 99% и 130%, 130%когда сборщик мусора работает в фоновом режиме.

...