スポンサーサイト

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

F#による並列プログラミング入門 (1) 非同期処理と並列処理の違い

 F#中級編で並列プログラミングについて3本ほどブログを書いたのですが、なかなか相手は巨大で、もっとじっくり、ゆっくり攻めるべきではないかと思い直し、別カテゴリとしてやりなおしてみたいと思います。他のエントリと同じで勉強したことをまとめるという形式なので、おかしいところ等ありましたら、ご指導等お願いいたします。 
 
Design Patterns for Decomposition and Coordination on Multicore Architectures  
からとなります。 
 
今回は「非同期処理と並列処理の違い」からです。 
まずは非同期処理のまとめです。 
 
非同期処理で用いられるスレッドは次の3種類 
(1)メインスレッド(プロセスの最初に作られるスレッド) 
(2)マニュアルスレッド 
      let t = new Thread(new ThreadStart(するべき仕事)) 
      t.Start() 
   とかいうようにThreadクラスのインスタンスを作ることで新規に起こすスレッド 
(3)プールスレッド 
      バックグラウンドタスクを起こすために、CLRの機能であるスレッドプール 
      (キューに入れられたリクエスト(処理)をスレッドプールが用意している 
       スレッドにより次々に実行していく仕組み)を使って実行されるスレッド 
       ThreadPool.QueueUserWorkItem (するべき仕事)とか 
       Begin..系のメソッドを利用することによって実行されます。 
 
        
なおどの場合でもスレッド毎にスタックメモリが準備されパラメータ情報や、プログラムのどこを実行中かのポインタ、さらにローカル変数が積み重なっていきます。スレッドで使う変数が値型でスタックに積まれる場合は、特に問題は起こらないのですが、スレッドで使う変数が参照型で、それが指し示すヒープ上の値が、他のスレッドからも参照されている場合や、ヒープ上のstaticな値を使用する場合は、複数のスレッドから同じタイミングで変更しようとすると、いわゆる「競合状態」がおこります 
(これを避けるためには、lockを使って、変更しようとしている間は、対象部分が他のスレッドから変更されないようにします。しかし安易に、この手法を使うとデッドロックなどの問題を引き起こします。) 
 
(immutableな値だけを使用する場合は競合状態の心配はありません。) 
 
競合状態が起こる心配をしなくてよい、関数等を「スレッドセーフ」であるといいます。 
 
またスレッドの種別としては、フォアグラウンドスレッドとバックグラウンドスレッドの二種類があり、スレッドのIsBackgroundプロパティにより変更できます。アプリケーションプロセスのすべてのフォアグラウンドスレッドが終了すると、プロセスが終了する形になります。 
 
スレッドプールを使う場合は、スレッドプールが用意しているスレッド数は限り(コア数*250?)があり、それをこえる分は、キュー(グローバルキュー)の中で、実行待ちになります。 
一方マニュアルスレッドは制限なしでスレッドが生成されていきますので、あまりに多いと、スレッド毎のスタックメモリの合計が大きくなりすぎ、メモリ不足を起こす場合があります。 
 
基本的には「仕事」ができたら、スイッチングされながらも、すぐ実行されていくのが非同期処理におけるスレッドです。タイムスライス(時間を細切れにする)して、定期的にユーザーのインプット等に対応したりする用途等でよく使用されます。(コア数が1でも複数でも適用可能です) 
 
一方並列処理は、大きな問題を複数の仕事(Task)に分割し、これを処理していく仕組みです。複数のCPUを最大限に有効活用していくことが主眼です。 
  
.NETの並列処理は拡張版スレッドプールというような感じでデザインされています。 
スレッドプールのグローバルキューの出口は一つしかないので、ここから仕事を取ってくる場合に渋滞が発生しやすいのですが、並列処理のスレッドは、それぞれにキュー(ローカルキュー)というものを持っています。仕事から仕事が次々に派生した場合、この派生した仕事をグローバルキューではなく、ローカルキューに次々押し込んでおきます。(押し込む側をプライベートエンドといいます)そして、やっている仕事が終わったら、プライベートエンド側から仕事を取り出して、その仕事を続けます。(キューというより、この部分はスタック的です。)ローカルキューが空になったら、グローバルキューを見に行き、仕事があればとってきて、その仕事を行います。グローバルキューも空のときは、他のキューのローカルキューを調べて、仕事が残っていたら、プライベートエンドと逆側(パブリックエンドといいます)から仕事を取り出して、その仕事をします。これにより、遊んでいるCPUを最小にするという効果を得ることができます。 
このような仕組みをwork-stealingといいます。こちらに図解がありますので、よろしければどうぞ。 
 
では次回から具体的な並列プログラミングを紹介していきます。 
 
なおスレッドの基本についてはこちらの記事が分かりやすく最高ですので、ご覧になることを強くおすすめします。 
また、Windowsプログラムでスレッドを利用する場合はさらに注意点があるので、興味ある方はこちら が超おすすめです。 
(どちらも「とあるコンサルタントのつぶやき」というブログの記事です。)
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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