C# を書いているときに、記録に残しておこうと思ったので個人的なメモとして書きます。ポリシーとしては自分が 検索エンジンに頼ったり、レビューを受けて学びを得たことを検証して理解して、次回からスピードアップできることを意図とししています。
- Pull Request APIs to enumerate all orchestration instances
検証1. List のコンストラクタ指定
Chris がレビューで、List のコンストラクタの数字は指定すること。指定しない場合、毎回領域を拡張するから遅いとのこと。実際コードを見てみる。
確かにそのとおりだ。デフォルトは empty の配列になっている。実際ためしてみよう。
var number = 100000000;
// Add 10000 instances to the List.
var watch = new Stopwatch();
watch.Start();
var list = new List<SomeClass>(number);
list.Add(
new SomeClass
{
Name = "ushio",
Age = 47
}
);
watch.Stop();
Console.WriteLine($"List With number constructor: {watch.ElapsedMilliseconds}");
watch.Restart();
list = new List<SomeClass>(number);
list.Add(
new SomeClass
{
Name = "ushio",
Age = 47
});
watch.Stop();
Console.WriteLine($"List without constructor: {watch.ElapsedMilliseconds}");
こんな感じでテストを実施。結果は以下の通り。小さいとそこまでインパクトありませんが、これぐらい回すと差が明確になるようです。
List With number constructor: 3
List without constructor: 1294
スレッドのスタベーション
あるasyncメソッドがあり、そのメソッドの実態はフラグが on の時だけ内部で async コールをするのだが、実体は型変換というメソッドがありました。わたしはその部分を読んでいなかったので単純に、Task.WhenAll
で並列処理させて早く終わらせようと考えました。このメソッドは1000程度のデータは来ることが想定されるのですが、彼から、メソッドスタベーションがおこるのでは?と指摘をうけました。結局のところ、リファクタリングして、型変換だけのメソッド抽出を行って解決したのですが、スレッドスタベーションが起こるかを試したくなりました。
public static async Task RunoutThreading()
{
var watch = new Stopwatch();
watch.Start();
var number = 100000;
var list = new List<Task>(number);
for(var i = 0; i < number; i++)
{
list.Add(SomeExecAsync());
}
watch.Stop();
Console.WriteLine($"RunoutThread finished: elapse : {watch.ElapsedMilliseconds}");
await Task.WhenAll(list);
}
これぐらいの並列処理でもさして時間かからず終了しました。
18346
これぐらいの並列でもスレッドスタベーションは起こりません。この理由ですが、呼ばれる対象のメソッドがこんな感じです。async/await
は賢いので、別スレッドを大量に作るとかはしないようです。本件はですので杞憂なのですが、よい知識の確認になりました。(むしろリファクタリングの問題w)
private static async Task SomeExecAsync()
{
Console.WriteLine($"SomeExecAsync(): Current: {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000 * 3);
}
結果
SomeExecAsync(): Current: 1
SomeExecAsync(): Current: 1
SomeExecAsync(): Current: 1
SomeExecAsync(): Current: 1
SomeExecAsync(): Current: 1
SomeExecAsync(): Current: 1
まとめ
そういえば過去にブログ書いてた