スポンサーサイト

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

F#による並行プログラミング入門(12) Parallel Tasks(1) Taskの生成実行,WaitAll,WaitAny

 前回までは、lEnumerable型の値に一つの関数を適用させていく作業をparallelで行う例でしたが、今回からは複数種類の関数実行をparallelに行う例の紹介です。 
 
これを行うにはSystem.Threading.Tasksクラスのインスタンスをそれぞれの実行する関数を材料として生成し、並行処理として走らせます。 
 
> open System 
open System.Threading 
open System.Threading.Tasks;; 
> let longTaskSubL r =  
    let res = ref 0L  
    for i in 1L .. 100000L do  
      for j in 1L .. 1000L do  
         res := !res + r  
    printfn "引数%Aに対しlongTaskSubの計算が終了" r 
    !res  
 
let doWorkL i = 
    longTaskSubL i |> ignore 
    printfn "引数%Aに対しManagedThreadId = %dで仕事を終わらせました"  i Thread.CurrentThread.ManagedThreadId;; 
 
val longTaskSubL : int64 -> int64 
val doWorkL : int64 -> unit 
 
ではTaskクラスのインスタンスを一つ作ってみます。 
 
> let task0 = new Task(fun () ->(doWorkL 2L));; 
val task0 : Task 
 
代表的なプロパティを見てみます。 
 
> task0;; 
val it : Task = System.Threading.Tasks.Task {AsyncState = null; 
                                             CreationOptions = None; 
                                             Exception = null; 
                                             Id = 1; 
                                             IsCanceled = false; 
                                             IsCompleted = false; 
                                             IsFaulted = false; 
                                             Status = Created;} 
                                              
 
開始するにはスタートメソッドを使います。 
 
> task0.Start() 
printfn "Task0 が終了しました";; 
 
Task0 が終了しました 
> 引数2Lに対しlongTaskSubの計算が終了 
引数2Lに対しManagedThreadId = 6で仕事を終わらせました 
 
少し不思議な状況になりました。「Task0 が終了しました」の表示の後に実際の仕事が終わっています。 
これは「taskを並行処理で開始した場合、その処理の終了を待たずに、メインスレッド側が処理を進めていっていること」が原因です。メインスレッド側で並行処理の終了を待って処理を進める場合は、待つ場所で、タスクのWaitメソッドを使います。(他にもいろいろ方法がありますが、それは後日順次紹介していきます。) 
ではさっきの部分をすこし修正します。 
 
> let task0 = new Task(fun () ->(doWorkL 2L)) 
task0.Start() 
task0.Wait() 
printfn "Task0 が終了しました";; 
 
引数2Lに対しlongTaskSubの計算が終了 
引数2Lに対しManagedThreadId = 5で仕事を終わらせました 
Task0 が終了しました 
 
次は2つのタスクを生成しスタートしてから、メインスレッド側で終了を待って、処理を同期したいと思います。2つ以上のタスクの終了を待つのはTask.WaitAllメソッドを利用します。引数はTask[] 型です。 
 
> let task0 = new Task(fun () ->(doWorkL 2L)) 
let task1 = new Task(fun () ->(doWorkL 1L)) 
task0.Start() 
task1.Start() 
Task.WaitAll [|task0;task1|] 
printfn "すべてのTask が終了しました";; 
 
引数1Lに対しlongTaskSubの計算が終了 
引数1Lに対しManagedThreadId = 4で仕事を終わらせました 
引数2Lに対しlongTaskSubの計算が終了 
引数2Lに対しManagedThreadId = 3で仕事を終わらせました 
すべてのTask が終了しました 
 
どれか少なくとも一つのタスクが終了するのを待つには、WaitAnyメソッドを使用します。 
引数はtask[]で、返り値は(最初に)終了したタスクのインデックスです。 
 
例 
 
> let task0 = new Task(fun () ->(doWorkL 3L)) 
let task1 = new Task(fun () ->(doWorkL 1L)) 
let task2 = new Task(fun () ->(doWorkL 2L)) 
 
let tasks = [|task0;task1;task2|] 
tasks |> Array.iter (fun t -> t.Start())  
let index = Task.WaitAny tasks 
printfn "タスク配列のindex:%dのタスクが終了しました。" index 
Task.WaitAll tasks 
printfn "すべてのTask が終了しました";; 
 
 
引数1Lに対しlongTaskSubの計算が終了 
引数1Lに対しManagedThreadId = 6で仕事を終わらせました 
タスク配列のindex:1のタスクが終了しました。 
引数3Lに対しlongTaskSubの計算が終了 
引数3Lに対しManagedThreadId = 4で仕事を終わらせました 
引数2Lに対しlongTaskSubの計算が終了 
引数2Lに対しManagedThreadId = 5で仕事を終わらせました 
すべてのTask が終了しました 
 
val task0 : Task 
val task1 : Task 
val task2 : Task 
val tasks : Task [] = 
  [|System.Threading.Tasks.Task; System.Threading.Tasks.Task; 
    System.Threading.Tasks.Task|] 
val index : int = 1 
 
なおタスクの生成と開始はTask.Factory.StartNewメソッドを利用するとワンステップでおこなうことができます。 
なお返り値は生成され開始されたTaskです。 
 
> let task00 = Task.Factory.StartNew(fun () -> doWorkL 1L) 
task00.Wait();; 
引数1Lに対しlongTaskSubの計算が終了 
引数1Lに対しManagedThreadId = 11で仕事を終わらせました 
 
val task00 : Task 
 
これを用いると先ほどの例は次のように書き直すことができます。 
 
> let tasks = 
    [|(fun () -> doWorkL 3L);(fun () -> doWorkL 1L);(fun () -> doWorkL 2L)|] 
    |> Array.map (fun f -> Task.Factory.StartNew f) 
let index = Task.WaitAny tasks 
printfn "タスク配列のindex:%dのタスクが終了しました。" index 
Task.WaitAll tasks 
printfn "すべてのTask が終了しました" 
;; 
 
引数2Lに対しlongTaskSubの計算が終了 
引数2Lに対しManagedThreadId = 14で仕事を終わらせました 
タスク配列のindex:2のタスクが終了しました。 
引数1Lに対しlongTaskSubの計算が終了 
引数1Lに対しManagedThreadId = 13で仕事を終わらせました 
引数3Lに対しlongTaskSubの計算が終了 
引数3Lに対しManagedThreadId = 12で仕事を終わらせました 
すべてのTask が終了しました 
 
val tasks : Task [] = 
  [|System.Threading.Tasks.Task; System.Threading.Tasks.Task; 
    System.Threading.Tasks.Task|] 
val index : int = 2 
 
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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