わんくま同盟 名古屋勉強会 #28
C#で、ライフ ゲームを高速化してみるよ
~ 「C#マルチコア本」発刊記念
2013/8/24
BluewaterSoft biac
1
わんくま同盟 名古屋勉強会 #28
スピーカー紹介
2
わんくま同盟 名古屋勉強会 #28
スピーカー紹介 • 1957: スプートニク以前
に誕生 (宇宙世紀未満)
• 1983: 名古屋大学工学部(修
士)卒
• HONDA R&Dで自動車設計
• 1994~ ソフトウェア業界
• 2012~ BluewaterSoft
biac (山本 康彦)
http://www.bluewatersoft.jp
3
わんくま同盟 名古屋勉強会 #28
スピーカー紹介 • 本を書いたり
biac (山本 康彦)
http://www.bluewatersoft.jp
速攻入門 C# プログラミング
技術評論社、共著
2012/3
Windows 8
業務アプリ開発読本
技術評論社、共著
2013/3
C#によるマルチコアのための非
同期/並列処理プログラミング
技術評論社
2013/7
今日の話は、
この第4部から!
4
わんくま同盟 名古屋勉強会 #28
スピーカー紹介 • 記事を書いたり
biac (山本 康彦)
http://www.bluewatersoft.jp WinRT/Metro TIPS
@IT ~ 連載中
http://www.atmarkit.co.jp/ait/subtop/features/da/ap_winrttips_index.html
C#で始めるテスト駆動開発入門
CodeZine
http://codezine.jp/article/corner/446
特集: 次期 Windows 8.1 &
Visual Studio 2013
Preview 概説
@IT 2013/7
http://www.atmarkit.co.jp/ait/articles/1307/19/news099.html
5
わんくま同盟 名古屋勉強会 #28
スピーカー紹介 • アプリを作ったり
biac (山本 康彦)
http://www.bluewatersoft.jp
6
わんくま同盟 名古屋勉強会 #28
スピーカー紹介 • 講師やったりしてます
biac (山本 康彦)
http://www.bluewatersoft.jp
C# / VB.NET による
Windows 8 アプリ開発入門
2013/10/30~31
名古屋ソフトウェアセンター
http://www.nagoya-sc.co.jp/ap/seminar?m=1&key=10734
7
わんくま同盟 名古屋勉強会 #28
新刊紹介
• 2013/7/20上梓
• 電子書籍版もあります
https://gihyo.jp/dp/ebook/2013/978-4-7741-5907-2
• C#はやってるけど、非同期/並列
処理は「?」という開発者に!
C#によるマルチコアのための
非同期/並列処理プログラミング
http://www.amazon.co.jp/dp/4774158283/?tag=bluewatersoft-22
8
わんくま同盟 名古屋勉強会 #28
新刊紹介
■はじめに
この本は第一に,.NET Framework で,非
同期処理,並列処理を効率良く実現できる
マルチスレッドのプログラムを作りたいと
思っている開発者のために書きました.
.NET Framework での(マルチスレッドで
はないプログラムの)開発経験があること
を前提にしています.
また,すでにマルチスレッドの経験のある
プログラマーにとっては,ハンドブックと
なるように,そして最新の.NET
Framework による効率的なプログラミング
を伝えられるようにと書き進めました.
C#によるマルチコアのための
非同期/並列処理プログラミング
http://www.amazon.co.jp/dp/4774158283/?tag=bluewatersoft-22
9
わんくま同盟 名古屋勉強会 #28
新刊紹介
■目次
Part 1 マルチコアのための非同期処理/並列
処理の原理
Chapter 1 マルチコアを使いこなす
非同期処理/ 並列処理の時代
Chapter 2 試して納得!
マルチコア活用プログラミングの原理とポイント
Part 2 マルチコアを使いこなすための非同
期/並列処理必須知識
Part 3 マルチコアのためのC#/.NETの非同
期/並列処理の方法
Part 4 マルチコア非同期/並列処理実践プロ
グラミング
C#によるマルチコアのための
非同期/並列処理プログラミング
http://www.amazon.co.jp/dp/4774158283/?tag=bluewatersoft-22
10
今日の話は、
ここから!
わんくま同盟 名古屋勉強会 #28
アプリを
高速化する手順
ようやく本題 f(^^;
11
わんくま同盟 名古屋勉強会 #28
一般的には、こんな順序で
非同期化
• 画面とロジックを非同期化
⇒ お互い足を引っ張らないように!
並列化
• ロジックを並列化
⇒ 並列処理にして処理時間を短縮
ロジック
• ロジックを改良してさらに高速化
※先にやっちゃうと、並列化がわけわかめ
12
わんくま同盟 名古屋勉強会 #28
LANGTON'S LOOPS
を高速化してみるよ!
お題
13
わんくま同盟 名古屋勉強会 #28
Langton's loops • セル・オートマトンの
一種
• 無限に自己増殖を
繰り返す
※ 右はラングトンのループの
初期状態。Wikipediaより。
14
わんくま同盟 名古屋勉強会 #28
Langton's loops • ルールに従って、次ス
テップの状態を計算する
• ルールの例
ラングトンのループは、
・セルの状態は0~7
・上下左右の隣のセルと
自身の値で次の状態が決まる
15
わんくま同盟 名古屋勉強会 #28
とりあえず見てみるのが早い!
16
わんくま同盟 名古屋勉強会 #28
ロジック側
public class LangtonsLoops {
//「世界」(intの2次元配列)
int[,] _lives;
public int[,] Lives { get { return _lives; } }
// セルオートマトンの規則
Rule _rule;
public void Update() {
// 隣を見る(観測し終わるまで_livesを変更してはいけない)
for (int r = 1; r < _size - 1; r++)
for (int c = 1; c < _size - 1; c++)
//…
// 次ステップの状態を計算して_livesを書き換える
for (int r = 1; r < _size - 1; r++)
for (int c = 1; c < _size - 1; c++)
//…
}
}
17
これは並列化
するしか!
でもそれは
後のお楽しみ♪
わんくま同盟 名古屋勉強会 #28
画面側
private async Task RunLoops()
{
while (_isRunning)
{
_langtonsLoops.Update(); //ロジックを1ステップ計算させる
UpdateBitmap(_langtonsLoops.Lives); //画面を更新する
await Task.Yield(); // 画面更新の機会を与える(DoEventsの代用)
}
}
18
計算中は
画面がフリーズ
画面更新中は
計算せず
わんくま同盟 名古屋勉強会 #28
速度計測結果(例) サイクル
タイム
性能向上 画面描画
速度
最初の実装 0.08秒 --- 12fps
※ あくまでも特定の条件で計測し
ただけの参考値です
19
わんくま同盟 名古屋勉強会 #28
画面とロジックが
足を引っ張り合わないように
まずは非同期化
20
わんくま同盟 名古屋勉強会 #28
画面をフリーズさせない非同期
private async Task RunLoops()
{
while (_isRunning)
{
// await Task.Runで囲って非同期にする
await Task.Run(()=>
_langtonsLoops.Update(); //ロジックを1ステップ計算させる
);
UpdateBitmap(_langtonsLoops.Lives); //画面を更新する
//await Task.Yield(); // DoEvents(の代用)は不要になった
}
}
21
・やっぱりロジックの後で画面更新
・やっぱり画面更新中は計算せず
わんくま同盟 名古屋勉強会 #28
ロジックを全速力で走らせる非同期(1/2)
public class LangtonsLoops { // ロジック側
// 変更を画面に通知するためのイベント
public event PropertyChangedEventHandler PropertyChanged;
public async Task RunLoopsAsync() {
// フラグが立っている間、非同期で計算し続ける
await Task.Run(() => {
while (_isRunning) {
Update();
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Lives"));
}
});
//…
}
// ……以下略……
22
わんくま同盟 名古屋勉強会 #28
ロジックを全速力で走らせる非同期(2/2)
public sealed partial class MainPage : LayoutAwarePage { // 画面側
// ロジックを起動する
private async Task RunLoops() {
//…
await _langtonsLoops.RunLoopsAsync();
}
// ロジックから呼び出されるイベントハンドラー
async void LangtonsLoops_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Lives") {
//…UpdateBitmapしてるときは、イベントを無視してここでリターン…
await _thisDispatcher.RunAsync( // UIスレッドで実行する
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { UpdateBitmap(_langtonsLoops.Lives); //…
});
//…
}
}
// ……以下略……
23
わんくま同盟 名古屋勉強会 #28
あれっ!? 排他は?
• 2 次元配列 Livesを双方からアクセスする
⇒ 排他制御しないとマズイんじゃね?
• よく考えてみる。
ロジック: Livesを読み書き
画面:Livesから読み出すだけ
中途半端に読み出しても、多少画面が乱れ
るだけ(たぶん誰も気付かない)
⇒ 排他制御しなくていいじゃん!
24
わんくま同盟 名古屋勉強会 #28
速度計測結果(例) サイクル
タイム
性能向上 画面描画
速度
最初の実装 0.08秒 --- 12fps
非同期化 0.05秒 1.6倍 16fps
※ あくまでも特定の条件で計測し
ただけの参考値です
25
わんくま同盟 名古屋勉強会 #28
ロジックで
マルチ コアをフルに使う
いよいよ並列化
26
わんくま同盟 名古屋勉強会 #28
ロジックを並列化する
public class LangtonsLoops {
//……省略……
public void Update() {
// 隣を見る(観測し終わるまで_livesを変更してはいけない)
Parallel.For(1, _size - 1, (r) => {
for (int c = 1; c < _size - 1; c++) {
//……隣を観測してメモリに保持……
}
});
// 次ステップの状態を計算して_livesを書き換える
Parallel.For(1, _size - 1, (r) => {
for (int c = 1; c < _size - 1; c++) {
//……隣の観測結果から、次ステップを計算し、_livesに書き込み
}
});
}
27
わんくま同盟 名古屋勉強会 #28
あれっ!? 排他は?
• 2 次元配列 Livesを、複数のスレッドから
アクセスする
⇒ 排他制御しないとマズイんじゃね?
• よく考えてみる。
アクセスする場所は?
r(行)とc(列)で指定された要素。
これはスレッドごとに異なる。
⇒ 排他制御しなくていいじゃん!
28
わんくま同盟 名古屋勉強会 #28
速度計測結果(例) サイクル
タイム
性能向上 画面描画
速度
最初の実装 0.08秒 --- 12fps
非同期化 0.05秒 1.6倍 16fps
並列化 0.03秒 2.7倍 8fps
※ あくまでも特定の条件で計測し
ただけの参考値です
29
わんくま同盟 名古屋勉強会 #28
ロジックを見直して
さらに高速化
最後にチューニング
30
わんくま同盟 名古屋勉強会 #28
ロジック自体を高速化
• 2 つのループを 1 つに
Lives配列を2つ用意して読み出しと書込みを別の配列
に。(1ステップごとに交換)
• 観測用の配列を廃止 (単純な変数に)
• ルールの内部表現をスリム化
ルール参照キーの生成: 乗算と加算 ⇒ ビット演算
その他いろいろ
31
わんくま同盟 名古屋勉強会 #28
速度計測結果(例) サイクル
タイム
性能向上 画面描画
速度
最初の実装 0.08秒 --- 12fps
非同期化 0.05秒 1.6倍 16fps
並列化 0.03秒 2.7倍 8fps
チューン 0.01秒 8倍 10fps
※ あくまでも特定の条件で計測し
ただけの参考値です
32
わんくま同盟 名古屋勉強会 #28
大事な事なので
もういちど
以上、完了
33
わんくま同盟 名古屋勉強会 #28
一般的には、こんな順序で
非同期化
• 画面とロジックを非同期化
⇒ お互い足を引っ張らないように!
並列化
• ロジックを並列化
⇒ 並列処理にして処理時間を短縮
ロジック
• ロジックを改良してさらに高速化
※先にやっちゃうと、並列化がわけわかめ
34
+ 排他制御は、よくよく考えて!
※不要なことも多い。ムダな排他は低速化とバグの元
わんくま同盟 名古屋勉強会 #28
今日のネタ
• 今日のソースコード
gihyo.jpのサポートページに
あります
http://gihyo.jp/book/2013/978-4-
7741-5828-0/support
C#によるマルチコアのための
非同期/並列処理プログラミング
http://www.amazon.co.jp/dp/4774158283/?tag=bluewatersoft-22
35
わんくま同盟 名古屋勉強会 #28
ご清聴ありがとうございました
36

わんくま名古屋#28(20130824) c#で、ライフゲームを高速化してみるよ