4. ThreadよりもTask
for (int i = 0; i < num; i++)
{
var t = new Thread(_ =>
b[i] = F(a[i])
);
}
for (int i = 0; i < num; i++)
{
Task.Run(() =>
b[i] = F(a[i])
);
}
×悪い例
○良い(まだマシ※な)例
データの数だけ
スレッド作成
Threadでなく
Task利用
※ この場合、ParallelクラスやParallel.Enumerableクラスが使いやすい
5. ThreadよりもTask
for (int i = 0; i < num; i++)
{
var t = new Thread(_ =>
b[i] = F(a[i])
);
}
for (int i = 0; i < num; i++)
{
Task.Run(() =>
b[i] = F(a[i])
);
}
×悪い例
○良い(まだマシ※な)例
データの数だけ
スレッド作成
Threadでなく
Task利用
※ この場合、ParallelクラスやParallel.Enumerableクラスが使いやすい
題材
• スレッドのコスト
• スレッド プール
6. 非同期I/O
using (var r = new StreamReader("some.txt"))
{
var t = r.ReadToEndAsync();
Console.WriteLine(await t);
}
using (var r = new StreamReader("some.txt"))
{
var t = Task.Run(() => r.ReadToEnd());
Console.WriteLine(await t);
}
Task.Run
+
同期I/O
非同期I/O用メソッド
×悪い例
○良い例
7. 非同期I/O
using (var r = new StreamReader("some.txt"))
{
var t = r.ReadToEndAsync();
Console.WriteLine(await t);
}
using (var r = new StreamReader("some.txt"))
{
var t = Task.Run(() => r.ReadToEnd());
Console.WriteLine(await t);
}
Task.Run
+
同期I/O
非同期I/O用メソッド
×悪い例
○良い例
題材
• CPU-boundとI/O-bound
• I/O完了ポート
8. データ競合
var count = 0;
Parallel.For(0, num, i =>
{
++count;
});
var count = 0;
Parallel.For(0, num, i =>
{
lock (sync)
++count;
});
期待通りに動かない
count == numにならない
lockをかけるととりあえず
期待通りにはなる
×悪い例
○良い(まだマシ※な)例
※ Interlocked.Incrementメソッド使えばlockなしでスレッド安全にインクリメントできる
性能を考えると、次節のスレッド ローカルを使う方がいい
58. 非同期I/O
using (var r = new StreamReader("some.txt"))
{
var t = r.ReadToEndAsync();
Console.WriteLine(await t);
}
using (var r = new StreamReader("some.txt"))
{
var t = Task.Run(() => r.ReadToEnd());
Console.WriteLine(await t);
}
Task.Run
+
同期I/O
非同期I/O用メソッド
×悪い例
○良い例
76. CAS※
• 特に重要なのがCAS命令
• .NET的にはInterlocked.CompareExchangeメソッド
※ compare and swapの略。比較しながら交換
Intel CPUの命令名称的には compare exchange
int CompareExchange(ref int loc, int value, int comp)
{
int ret = loc;
if (ret == comp)
loc = value;
return ret;
}
↓こういう意味のコードを原子性保証付きで実行する命令
比較しながらの値の交換
77. CAS
• 何が重要かというと
• 競合が起きたことを検知できる
• 「競合を避ける」よりははるかに低コスト
int CompareExchange(ref int loc, int value, int comp)
{
int ret = loc;
if (ret == comp)
loc = value;
return ret;
} 競合してたら元のlocとは違う値が返る
78. 新実装がやってること
• 競合が見つかったらやりなおし
add
{
EventHandler handler2;
var disposed = _disposed;
do
{
handler2 = disposed;
var handler3 = (EventHandler)Delegate.Combine(handler2, valu
disposed = Interlocked.CompareExchange(ref _disposed, handle
}
while (disposed != handler2);
}
競合検知しながらの交換
競合してたら最初からやりなおし
いわゆる「楽観的排他制御」
eventの+=が競合することはほとんどないので、ほぼ1発