How does Scala use all my kernels here?

object PrefixScan {
  sealed abstract class Tree[A]
  case class Leaf[A](a: A) extends Tree[A]
  case class Node[A](l: Tree[A], r: Tree[A]) extends Tree[A]

  sealed abstract class TreeRes[A] { val res : A }
  case class LeafRes[A](override val res: A) extends TreeRes[A]
  case class NodeRes[A](l : TreeRes[A], override val res: A, r: TreeRes[A]) extends TreeRes[A]

  def reduceRes[A](t: Tree[A], f:(A,A)=>A): TreeRes[A] = t match {
    case Leaf(v) => LeafRes(v)
    case Node(l, r) => {
      val (tL, tR) = (reduceRes(l, f), reduceRes(r, f))
      NodeRes(tL, f(tL.res, tR.res), tR)
    }
  }
}

I am concerned about the function reduceRes.

It works ... the result of the calculations is great!

However, I went and implemented another version reduceResParthat uses fork-join in the first few branches to parallelize the calculation. But this did not accelerate.

Then I came back and realized .. the above version reduceResalready uses all 12 cores on my machine! How can I do that? I thought it would be just 1 core!

This code is from a parallel programming course at Coursera. In the last lecture of week 2, we study parallel prefix scan operations.

+6
source share
1 answer

How can I do that? I thought it would be just 1 core!

, , , . , , , .

, , , .

, , , . Windows, WinAPI, GetCurrentProcessorNumber(), , , JNA :

build.sbt:

"net.java.dev.jna" % "jna" % "4.4.0"

Java:

import com.sun.jna.Library;
import com.sun.jna.Native;

public class ProcessorNumberNative {

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
                Native.loadLibrary("Kernel32.dll",
                        CLibrary.class);

        Integer GetCurrentProcessorNumber();
    }
}

a println :

def reduceRes[A](t: Tree[A], f: (A, A) => A): TreeRes[A] = t match {
  case Leaf(v) =>
    println(s"Logical Processor Number: ${ProcessorNumberNative.CLibrary.INSTANCE.GetCurrentProcessorNumber()}")
    LeafRes(v)

  case Node(l, r) => 
    println(s"Logical Processor Number: ${ProcessorNumberNative.CLibrary.INSTANCE.GetCurrentProcessorNumber()}")
    val (tL, tR) = (reduceRes(l, f), reduceRes(r, f))
    NodeRes(tL, f(tL.res, tR.res), tR)
}

:

def main(args: Array[String]): Unit = {

  val tree = Node(Leaf(1),
                Node(Leaf(2),
                     Node(Node(Leaf(24), Leaf(30)),
                          Node(Leaf(3), Node(Leaf(10), Leaf(52))))))

  reduceRes(tree, (a: Int, b: Int) => a + b)
}

( 4 ):

-:

Logical Processor Number: 1
Logical Processor Number: 3
Logical Processor Number: 3
Logical Processor Number: 3
Logical Processor Number: 0
Logical Processor Number: 0
Logical Processor Number: 0
Logical Processor Number: 3
Logical Processor Number: 0
Logical Processor Number: 0
Logical Processor Number: 0
Logical Processor Number: 0
Logical Processor Number: 0

-:

Logical Processor Number: 1
Logical Processor Number: 3
Logical Processor Number: 1
Logical Processor Number: 1
Logical Processor Number: 1
Logical Processor Number: 1
Logical Processor Number: 1
Logical Processor Number: 1
Logical Processor Number: 3
Logical Processor Number: 3
Logical Processor Number: 3
Logical Processor Number: 3
Logical Processor Number: 3

, 3 , 0, 1 3, . , , , .

+4

All Articles