非同期処理について
木曜日, 3月 30th, 2017こんにちは、naoyaです。
毎月一回のプログラミング学習記事の投稿になります。
第6回(最終回)は、「非同期処理」について、調べたことをまと
めていこうと思います。
・マルチスレッド
スレッドとは、一連の処理の流れのことを言う。処理の流れが
一本道なものをシングルスレッド、複数の処理を並行して行うも
のをマルチスレッドという。
何か非常に時間のかかる処理があるとすると、処理を行ってい
る間、計算に専念してもいいならシングルスレッドで問題ないが、
計算中に他の入力を受け付けたい場合がある。アクションゲーム
などでは、キャラクターの動きの計算をしている間、ユーザーか
らの入力を受け付けないようでは、アクションゲームとして成り
立たない。このような場合、ユーザーからの入力を受け付けるス
レッドと計算を行うスレッドを並行して動かす。
要するに、重たい処理を行っている間でもプログラム全体がフ
リーズしてしまわないようにするために、複数の処理を並行して
行うのが、マルチスレッドプログラミング。
・C#におけるマルチスレッドプログラミング
多くの場合、C#ではスレッドを直接作ることはほとんどない。
スレッドの新規作成やスレッド間の処理の切替は、結構重た
い処理で、最小限に抑えたい。そこで、実際にはスレッドを直
接使うのではなく、一度作ったスレッドを使いまわす仕組み
(スレッドプール)を使う。
・排他制御
マルチスレッドプログラムでは、複数のスレッドが一つのデー
タに対して操作することがある。何も考えず、ただ素直にプログ
ラミングを行うと、意図しない結果になる場合がある。
そのような問題を解決するために、排他制御というものが必要
になってくる。排他制御とは、複数のスレッドが同時に一つの
データを読み書きしないように制御することをいう。
・C#における排他制御
スレッドの排他制御を行う為には、同期オブジェクトと排他
ロックという概念を用いる。考え方としては、排他制御が必要
になる部分に入る前に、あるオブジェクトに鍵をかける。鍵が
かかっている間、他のスレッドは同じオブジェクトには鍵をか
けることができず、鍵が外されるまで待たされる。そして、鍵
をかけたスレッドが排他制御が必要な部分を抜けると、鍵を外
す。
鍵をかけるオブジェクトを「同期オブジェクト」、鍵をかけ
る行為を「排他ロック」という。
・非同期処理の種類
「非同期処理」といっても、いくつかタイプがあり、それぞれ
書き方などが異なる。大まかにいうと、以下の用途がある。
・バックグラウンド処理:負荷の高い計算や、I/O待ちなどで、
CPUやスレッド資源を保持し続けないために、別スレッドで計
算やI/O待ちを行う。
・並列計算:マルチコアCPUの性能を最大限引き出すために、
同じ計算を複数のコアで同時に実行する。
・データ並列:同じ処理を異なるデータに対して行う。
・タスク並列:異なる処理が独立して動いていて、その間に
非同期でデータのやり取りを行う。
・バックグラウンド処理
負荷の高い計算やI/O待ちをする場合、メインスレッドとは
別のスレッドを使いたい場合がある。例えば、GUIアプリの場
合、メインスレッドで時間のかかる処理を行うと、アプリがフ
リーズしてしまい、ユーザーに与える印象が非常に悪くなって
しまう。メインスレッド以外で行う処理の事を、バックグラウ
ンド処理という。
バックグラウンド処理では、バックグラウンドで行った処理
の結果の値を受け取って、メインスレッドで処理を行いたい場
合が多い。
・利点
GUIの応答性向上:時間のかかる処理を行っている間、UIス
レッド(GUIにおける、エンドユーザーからの入力を受け付け
るためのスレッド)をブロックせず、フリーズを回避できる。
スレッド資源の節約:I/O待ちにしている間、スレッドを解
放することによって、メモリ(スレッド用のスタック等)やCP
U(コンテキストスイッチ等)の負担を減らせる。
・データ並列
並列処理も、非同期処理の一種になる。並列処理を行いたい
動機は、マルチコアCPUの性能を最大限に引き出すこと。その
一番シンプルな方法は、同じ処理を、異なるデータに、複数の
コアで同時に実行すること。このような並列処理を、データ並
列と呼ぶ。
・タスク並列(非同期データフロー)
並列処理を行うもう一つの方法としては、異なる処理(タス
ク)を独立して動かして、その間で、非同期でデータのやり取
りを行う方法がある。異なるタスクを並列に動かすという意味
では、タスク並列。非同期でデータをやり取りするという意味
では、非同期データフローと呼ばれる。
今回マルチスレッドについて学ぶよりも前に、一度開発でマルチ
スレッドを扱う機会があり、学びなおすにあたって、その時にやっ
ていた事を思い出しながら学ぶことができました。「この失敗は前
の時やってたな」とか思う部分もあり、そういった部分を今回学び
なおせたので、次回マルチスレッドを使う機会があれば、こういっ
た失敗をしないように、気を付けていこうと思います。
今回で一応最終回となりますが、勉強は続けるので、もしかした
らどこかのタイミングで何か書くかもしれません。その時はまた、
アドバイスなどをよろしくお願いします。