はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unity2020.3.32f1でEnumerable.ReverseよりもArray.Reverseがめちゃ遅いんだが??

はじめに

Unityを触っていて、なんだかArray.Reverseが遅く、Enumerable.Reverseにしてみたら速くなったという不思議な現象に出会いました。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.reverse?view=net-6.0
https://docs.microsoft.com/ja-jp/dotnet/api/system.array.reverse?view=net-6.0

環境
  • Unity2020.3.32f1
  • macOS Monterey

私の認識だと一般的にArray.Reverseの方がEnumerable.Reverseよりも処理速度が速いと思っていたのですが、案外そうではないんですかね。

というわけで調べてみました。

Unity2020での検証

環境
  • Unity2020.3.32f1
  • .NET Standard2.0
  • Mono
  • macOS Monterey
private void Start()
{
    var array = Enumerable.Range(0, 100000000)
        .ToArray();

    var sw = new Stopwatch();

    // Array.Reverse
    sw.Start();
    Array.Reverse(array);
    sw.Stop();

    Debug.Log($"Array.Reverse : {sw.ElapsedMilliseconds}ms");
        
    // 同じ実験対象にするために順番を戻しておく
    array = array.Reverse().ToArray();
        
    // Enumerable.Reverse
    sw.Reset();
    sw.Start();
    array = array.Reverse().ToArray();
    sw.Stop();
        
    Debug.Log($"Enumerable.Reverse : {sw.ElapsedMilliseconds}ms");
}
メソッド 処理速度
Array.Reverse 100952ms
Enumerable.Reverse 515ms


Array.Reverseがやたら遅いですね。ちなみに実行する順番を変えたりしても同じ結果になりました。

.Net Framework v4.8のConsoleアプリケーション

今度はUnityを利用せずに、Riderを利用してConsoleアプリを作成して計測してみます。

環境
  • macOS Monterey
  • .Net Framework v4.8
  • Rider2020.3.4
public static void Main(string[] args)
{
    var array = Enumerable.Range(0, 100000000)
        .ToArray();

    var sw = new Stopwatch();

    // Array.Reverse
    sw.Start();
    Array.Reverse(array);
    sw.Stop();

    Console.WriteLine($"Array.Reverse : {sw.ElapsedMilliseconds}ms");
        
    // 同じ実験対象にするために順番を戻しておく
    array = array.Reverse().ToArray();
        
    // Enumerable.Reverse
    sw.Reset();
    sw.Start();
    array = array.Reverse().ToArray();
    sw.Stop();
        
    Console.WriteLine($"Enumerable.Reverse : {sw.ElapsedMilliseconds}ms");
}
メソッド 処理速度
Array.Reverse 63058ms
Enumerable.Reverse 534ms

Unityを利用しなくてもArray.Reverseが極端に遅いですね。うーん。

.Net Core 3.1のコンソールアプリケーション

なんかこのまま終わるのが癪なので、.Net Coreを利用し、Visual Studioでやってみます。

環境
  • macOS Monterey
  • .Net Core 3.1
  • VisualStudio for Mac v17.0.5
メソッド 処理速度
Array.Reverse 53ms
Enumerable.Reverse 288ms


まさかの結果になってしまいました。圧倒的にArray.Reverseの方が早いですね。

.Net 5.0のコンソールアプリケーション

次は.NET 5.0

環境
  • macOS Monterey
  • .Net 5.0
  • VisualStudio for Mac v17.0.5
メソッド 処理速度
Array.Reverse 59ms
Enumerable.Reverse 351ms

これもArray.Reverseの勝利です。

Unity2021での検証

環境
  • Unity2021.3.0f1
  • .NET Standard2.1
  • macOS Monterey
メソッド 処理速度
Array.Reverse 63ms
Enumerable.Reverse 443ms

普通にArray.Reverseが勝ちました。2021.Net Standard2.1に対応したのでこれが原因なのでしょうか。

Unity2019

環境
  • Unity2019.4.0f1
  • .NET Standard2.0
  • Mono
  • macOS Monterey
メソッド 処理速度
Array.Reverse 128206ms
Enumerable.Reverse 484ms
  • Unity2019.4.0f1
  • .NET 4.x
  • Mono
  • macOS Monterey
メソッド 処理速度
Array.Reverse 125947ms
Enumerable.Reverse 440ms

ひとこと

Unity2021以上か未満かで速度にかなりの違いがでてきていました。

おそらく.NETのバージョンによる違い?なのかなとも思いますが、他の要因なのかもしれません。

Array.ReverseO(n)なはずですし、なにかが悪さしている気がします。

何か知っている方がいましたらコメント等で教えていただけますと幸いです。

追記