2017-08-10 23 views
6
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) 
    } 
    } 
} 

我很關心reduceRes函數。Scala如何在這裏使用我所有的核心?

它的工作原理...計算的結果是偉大的!

但是我去實現了另一個版本reduceResPar,它在前幾個分支中使用fork-join來並行計算。但它沒有加速。

然後我回去實現..上述版本reduceRes已經在我的機器上使用了所有12個核心!它怎麼能這樣做?我認爲這只是一個核心!

此代碼來自Coursera的並行編程課程在第2周的最後一堂課中,我們正在學習並行前綴掃描操作。

+0

你確定使用多個核心嗎?真的看起來沒有機會在這個來源的任何併發 - 沒有平行的集合,沒有期貨... – Suma

+0

你可能會發佈一個更完整的例子,包括你如何創建樹實例並運行'reduceRes'? – Suma

+0

我與使用此代碼的katie具有相同的問題:https://pastebin.com/dNFMxN7F雖然沒有機會使用所有內核 – rubiktubik

回答

4

它怎麼能這樣做?我認爲這只是一個核心!

您看到所有正在使用的核心並不意味着您的代碼執行是並行的。我們可以從實現中看到它是連續的,但是我們不知道在每個週期中,我們的單個線程將由操作系統調度到哪個CPU。

當您在一個線程內執行一個方法時,操作系統會根據它管理的優先級隊列決定它將得到的CPU時間片數以及時間片的數量。

爲了看到你的算法可以在不同的內核上運行,我們可以詢問操作系統在哪個邏輯核心上執行我們的線程。我爲Windows準備了一個小型實現,它具有一個名爲GetCurrentProcessorNumber()的原生WinAPI方法,該方法返回我們正在執行的處理器編號。我們將使用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(); 
    } 
} 

現在,讓我們每個在你的遞歸步驟添加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上得到了一個執行片,而我們仍然在一個單線程中運行vironment。這表明,儘管算法的計算絕對是順序的,但這並不意味着您不會看到所有核心在使用。

相關問題