developer's diary

最近はc#のエントリが多いです

C# (dotnetcore) yield returnイテレーターは使った方が良いのか?

Mac Book Prodの dotnetcore3.1 で確認しました。

結論

結論からいうと、yield returnイテレーターを利用すると、メモリが節約され、若干時間が早くなった。

今回、指定したフォルダ配下のファイルを抽出する関数を、

Listと、IEnumerableでそれぞれ作成し、

Listに溜めて返却するパターンと、yield returnするパターンに分けて確認してみた。

IEnumerableでyield returnするパターンの関数

        static IEnumerable<string> fileList(string path)
        {
            foreach (var f in System.IO.Directory.GetFiles(path))
            {
                yield return f;
            }
            foreach (string dir in System.IO.Directory.GetDirectories(path))
            {
                foreach (var f in fileList(dir))
                {
                    yield return f;
                }
            }
        }

Listに溜めて返却するパターンの関数

        static List<string> fileList2(string path)
        {
            List<string> result = new List<string>();

            result.AddRange(System.IO.Directory.GetFiles(path));
            foreach (string dir in System.IO.Directory.GetDirectories(path))
            {
                result.AddRange(fileList2(dir));
            }
            return result;
        }

呼び出し側のソース

        static void Main(string[] args)
        {
            for(int i = 0;i<10; i++)
            {
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                int count = 0;
                foreach (string path in fileList2("/Applications/Visual Studio.app/"))
                {
                    //Console.WriteLine(path);
                    count++;
                }
                sw.Stop();
                Console.WriteLine("ファイル数:{0:#,0}", count);
                Console.WriteLine("利用メモリ:{0:#,0}", Environment.WorkingSet);
                Console.WriteLine("実行時間:{0:#,0} ms", sw.ElapsedMilliseconds);
            }
        }

fileList2か、fileListと呼び出しを分けてそれぞれ確認しました。

計測結果

IEnumerable パターン

ファイル数:13,980 利用メモリ:21,479,424 実行時間:140 ms

ファイル数:13,980 利用メモリ:22,523,904 実行時間:120 ms

ファイル数:13,980 利用メモリ:26,517,504 実行時間:124 ms

ファイル数:13,980 利用メモリ:23,904,256 実行時間:108 ms

ファイル数:13,980 利用メモリ:26,537,984 実行時間:109 ms

ファイル数:13,980 利用メモリ:21,397,504 実行時間:104 ms

ファイル数:13,980 利用メモリ:21,639,168 実行時間:105 ms

ファイル数:13,980 利用メモリ:23,719,936 実行時間:109 ms

ファイル数:13,980 利用メモリ:22,876,160 実行時間:118 ms

ファイル数:13,980 利用メモリ:23,158,784 実行時間:109 ms

実行時間平均:114.6 ms 利用メモリ平均:23,375,462.4

Listに溜めて返却するパターン

ファイル数:13,980 利用メモリ:28,090,368 実行時間:145 ms

ファイル数:13,980 利用メモリ:35,373,056 実行時間:127 ms

ファイル数:13,980 利用メモリ:40,423,424 実行時間:112 ms

ファイル数:13,980 利用メモリ:49,569,792 実行時間:112 ms

ファイル数:13,980 利用メモリ:58,970,112 実行時間:108 ms

ファイル数:13,980 利用メモリ:60,899,328 実行時間:126 ms

ファイル数:13,980 利用メモリ:64,606,208 実行時間:106 ms

ファイル数:13,980 利用メモリ:55,943,168 実行時間:124 ms

ファイル数:13,980 利用メモリ:42,098,688 実行時間:106 ms

ファイル数:13,980 利用メモリ:47,419,392 実行時間:109 ms

実行時間平均:117.5 ms 利用メモリ平均:48,339,353.6