Grand Central Dispatchを試してみる
Mac OS X 10.6 Snow Leopardはユーザー視点でみると変化が少なく面白いものがあまり無いリリースとなっていますが、テクノロジーの側面からみるといくつか売りとなっているものがあります。
具体的には下記の通りです。
- 64bit
- Grand Central Dispatch
- OpenCL
- QuickTime X
この中で64bit対応については特に面白いこともなく、OpenCLについては私の持っている機種が非対応のため試すことができませんが、Grand Central Dispatchは試せそうなので試してみました。
尚、Grand Central Dispatchの詳細を知りたい方は、リファレンスをご覧ください。
Documentation Archive
Grand Central Dispatchとは
まず、CPUの進化について。
以前のCPUの進化はクロックを高めることで処理能力を向上させていましたが、クロック向上による発熱問題が大きくなってきたため、最近の傾向としてはマルチコアにすることで性能を向上させています。
マルチコアとなったCPUを活用するためには、マルチスレッドに対応したソフトウェアを開発する必要がありますが、マルチスレッドプログラムは多くのプログラマにとって難しいもの(作ることよりもデバッグすることが。)である為、開発に消極的です。
また、ハイパフォーマンスなマルチスレッドプログラムを開発する為には、生成したスレッドを再利用したりするためにスレッドやタスクを管理するライブラリを作りますが、おそらく、そのライブラリを作るまでに多くのバグを生み出すことになるでしょう。
Grand Central Dispatchはスレッドを効果的に管理する為の仕組みです。
今までスレッド管理機構は自前で用意する必要がありましたが、Grand Central Dispatchはその代用となります。
またOSレベルでサポートされているため、自前で管理するよりもパフォーマンスも良いかもしれません。(未確認)
タスク
Grand Central Dispatchでは処理をブロック単位に分けてキューに登録します。
これをタスクといいます。
システムは開いているCPUコアがあると、タスクキューの先頭からタスクを取り出して順次実行します。
実行されるタスクは先入先出であるキューに登録されている為、実行順が保証されています。
キューはグローバルキューとプライベートキューを扱うことが可能ですが、詳細については、もう少し勉強してから順次書いていきたいと思います。
タスクの記述は、
^{ printf("Hello World!\n"); }
のように、『^{』と『}』で囲んで記述します。
このタスクをキューに追加するにはdispatch_xxxxxという関数を使用します。
同期処理の場合のdispatch_sync、非同期の場合のdispatch_async等、いくつか関数がありますが、詳細はリファレンスをご覧ください。
サンプル
簡単なサンプルを提示します。
#include <stdio.h> #include <unistd.h> #include <dispatch/dispatch.h> int main (int argc, const char * argv[]) { for (int i = 1; i <= 10; ++i) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ printf(" %d", i); }); } printf("\nDone!\n"); sleep(10); return 0; }
1から10まで表示させるだけの簡単なプログラムです。
『^{』と『}』で囲まれた部分が一つのブロックとなりタスクとして解釈されます。
dispatch_async関数で、dispatch_get_global_queue関数で取得したグローバルキューにタスクを追加しています。
実行結果は次のようになります。
1 2 Done! 3 4 5 6 7 8 9 10
dispatch_async関数でキューに追加しているため、処理の終了を待たずに非同期で実行されます。
その為、数を数えてタスクをキューに追加する処理と、数を表示する処理が並列で実行されるため、タスクをキューに追加する処理が表示の終了を待たずに終了し、後から表示処理が実行されます。
今回、Grand Central Dispatchの触りだけ試してみましたが、機会をみてもう少し調べてみたいと思います。