LoginSignup
1
2

More than 5 years have passed since last update.

C# : 学びのメモ (1) List と スレッドスタベーション

Posted at

C# を書いているときに、記録に残しておこうと思ったので個人的なメモとして書きます。ポリシーとしては自分が 検索エンジンに頼ったり、レビューを受けて学びを得たことを検証して理解して、次回からスピードアップできることを意図とししています。

検証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

まとめ

そういえば過去にブログ書いてた

リソース

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2