スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#による並列プログラミング入門 (2) Parallel Loops(1)

 まずはサンプル用に「少々処理に時間がかかる関数」を一つ定義しておきます。  
  
let longTaskSub r =  
    let res = ref 0  
    for i in 1 .. 100000 do  
      for j in 1 .. 1000 do  
         res := !res + r  
    !res   
  
これは引数に対しそれを100000*1000倍した値を返すという計算量だけはあるが全く役にたたない関数です。 
 
ではParallel.Forの紹介からです。 
これはforループのparallel版で次のような構文で使われます。(オーバーロードも多数あります。) 
 
Parallel.For(int fromInclusive,  
             int toExclusive,  
             Action<int> body); 
 
第3引数のbodyeはloop変数を引数としunit型を返すdelegateであるSystem.Action<T>ですが、int->unit型の関数を書いておけば、System.Action<int>型に変換してくれます。 
第一引数のfromInclusiveはループ変数の最小値(Inclusiveは含むという意味)で、第二引数のtoExclusive(Exclusiveは含まないという意味)はループ変数の(最大値 + 1)です。 
つまりParallel.For(1,100,関数)で、1以上99以下の整数に対して、関数が適用されます。 
注意すべき点は、1から99まで順に適用されるというわけではなく、それぞれの数に対しバラバラに(原則的に順不同)で関数は実行されるという点です。 
 
ではこのことを確かめてみます。 
 
pen System 
open System.Threading 
open System.Threading.Tasks 
 
let longTaskSub r =  
    let res = ref 0  
    for i in 1 .. 100000 do  
      for j in 1 .. 1000 do  
         res := !res + r  
    !res  
 
let doWork i = 
    longTaskSub i |> ignore 
    printfn "引数%dに対しManagedThreadId = %dで仕事を終わらせました"  i Thread.CurrentThread.ManagedThreadId 
 
Parallel.For(1,100,(fun i -> doWork i)) |> ignore 
printfn "すべて終了しました" 
 
runします。 
 
引数73に対しManagedThreadId = 5で仕事を終わらせました 
引数49に対しManagedThreadId = 6で仕事を終わらせました 
引数1に対しManagedThreadId = 1で仕事を終わらせました 
引数25に対しManagedThreadId = 3で仕事を終わらせました 
引数97に対しManagedThreadId = 4で仕事を終わらせました 
引数74に対しManagedThreadId = 5で仕事を終わらせました 
引数26に対しManagedThreadId = 3で仕事を終わらせました 
引数2に対しManagedThreadId = 1で仕事を終わらせました 
引数50に対しManagedThreadId = 6で仕事を終わらせました 
引数98に対しManagedThreadId = 4で仕事を終わらせました 
引数75に対しManagedThreadId = 5で仕事を終わらせました 
引数27に対しManagedThreadId = 3で仕事を終わらせました 
引数3に対しManagedThreadId = 1で仕事を終わらせました 
引数51に対しManagedThreadId = 6で仕事を終わらせました 
引数76に対しManagedT引数99に対しManagedThhreadId = 5で仕事を終わらせました 
eadId = 4で仕事を終わらせました 
引数4に対しManagedThreadId = 1で仕事を終わらせました 
引数28に対しManagedThreadId = 3で仕事を終わらせました 
引数52に対しManagedThreadId = 6で仕事を終わらせました 
引数77に対しManagedThreadId = 5で仕事を終わらせました 
引数8に対しManagedThreadId = 4で仕事を終わらせました 
引数5に対しManagedThreadId = 1で仕事を終わらせました 
中略 
引数96に対しManagedThreadId = 5で仕事を終わらせました 
引数71に対しManagedThreadId = 6で仕事を終わらせました 
引数72に対しManagedThreadId = 6で仕事を終わらせました 
すべて終了しました 
続行するには何かキーを押してください . . . 
 
スレッドIDが4のスレッド板が処理している仕事は、引数が97->98->99->8となっています。 
ということでParallelループでは、「順に処理されているわけではない」という点に十分注意を払う必要があります。 
もう一点留意するべき点があって、呼び出し側(この場合メインスレッド側)で、実行される「printfn "すべて終了しました"」の行はParallelループがすべて終了した後に呼び出されるということです。すなわち、呼び出し側の実行はParallelループが終了するまでブロックされるという点です。 
 
通常のforループは「indexが次々インクリメントされていく」というイメージですが、Parallelループは、「処理すべきindexの集合があって、いくつかのスレッドがそこから次々に数を取ってきては、スレッド上で関数(body部分)を実行する」というイメージです。 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。