.NETエンジニア・プログラマ向けの技術情報・業界ニュースをお届けします。

  1. FEnet.NETナビ
  2. .NETコラム
  3. プログラミング言語
  4. C#
  5. C#の高速化テクニックを伝授します!

C#の高速化テクニックを伝授します!

  • C#
  • プログラミング言語
公開日時:   更新日時:
C#の高速化テクニックを伝授します!
この記事でわかること
    基本情報技術者試験の試験対策はこちら>>
    システム
    エンジニア
    C#の実行を高速化する方法を教えていただけませんか。
    プロジェクト
    マネージャー
    C#のプログラミングでは効率の良いコードを記述して高速化することができます。

    C#の高速化とは


    今の時代の開発環境は自動的に最適化してくれるので、高速化はあまり考慮する必要が無いと言われます。それでも全く気を付けないのと、高速化を意識するのとでは動作速度にかなり差が出てきます。

    今回はC#のプログラミングにおける高速化のテクニックを紹介します。是非これを読んで効率の良いコードを記述してください。

    クラスと構造体

    C#の高速化と言われて真っ先に上がるのが構造体の使用の推奨です。以下のC#サンプルをご覧ください。

    public class TestC
    {
    public int val;
    }
    public struct TestS
    {
    public int val;
    }

    public static void Main()
    {
    var stopWatch = new System.Diagnostics.Stopwatch();
    stopWatch.Start();

    for (int i = 0; i < 1000000; i++)
    {
    TestC c = new TestC();
    c.val = 100;
    TestMethodC(c);
    }

    stopWatch.Stop();

    Console.WriteLine(stopWatch.ElapsedMilliseconds + “ミリ秒”);
    }

    public static int TestMethodC(TestC c)
    {
    return c.val;
    }
    public static int TestMethodS(TestS s)
    {
    return s.val;
    }

    クラスと構造体の実行速度を比較する

    上のサンプルは、クラスを生成してメンバフィールドに100を入れてそれを他のメソッドに渡す、という処理を100万回繰り返し、その実行時間の計測をしています。これを実行すると私のPCの環境では60ミリ秒前後という結果になります。

    ではforループの中身を以下のように変えてみてください。クラスを構造体に差し替えただけでやることは同じです。

    TestS s = new TestS();
    s.val = 100;
    TestMethodS(s);

    クラスと構造体の違い

    変更して実行すると、私のPC環境では12ミリ秒前後になります。実に5倍の差がでます。もしstructを使って無かったらと思うと怖いくらいの高速化ですね。なぜこれほどまでに差が出るのでしょうか。

    C#の構造体はクラスに比べて継承が出来ないなど、一部の機能がありません。そして最大の違いは、構造体は型が値型であるのに対し、クラスは参照型であることです。この違いが速度の差を生むのです。

    クラスは参照渡し、構造体は値渡し

    上のC#サンプルではメソッドにクラスや構造体をパラメータとして渡していますが、この時にクラスはインスタンスの参照を渡し、構造体は値を直接渡します。C#では後者の方がずっと速いのです。

    では、どんな時も常に構造体の方がずっと速いのでしょうか?実はそうではないのです。ここまでのC#サンプルを以下のように変えてみましょう。

    public class TestC
    {
    public int[] val;
    }
    public struct TestS
    {
    public int[] val;
    }

    public static void Main()
    {
    var stopWatch = new System.Diagnostics.Stopwatch();
    stopWatch.Start();

    for (int i = 0; i < 1000000; i++) { TestC c = new TestC(); c.val = new int[100]; for (int j = 0; j < c.val.Length; j++) { c.val[j] = j; } TestMethodC(c); } stopWatch.Stop(); Console.WriteLine(stopWatch.ElapsedMilliseconds + "ミリ秒"); } public static int TestMethodC(TestC c) { return c.val[0]; } public static int TestMethodS(TestS s) { return s.val[0]; }

    構造体で高速化できるのはデータサイズが小さい時だけ

    C#サンプルのクラスと構造体のフィールドを配列にし、int型で100の値を格納して同じ処理をしています。これでクラスと構造体の速さの違いを見てみましょう。結果は、私のPC環境ではどちらも1800ミリ秒前後になります。変わらなくなってしまいました。

    このようにクラスと構造体はデータサイズが大きくなると、差が無くなるのです。つまり、構造体で高速化できるのはデータサイズの小さい時だけ、ということになります。高速化できるからと言って何でもかんでもクラスを構造体にするのはやめましょう。

    文字列操作にはStringBuilderを使用する

    次は文字列操作についてです。以下のC#サンプルを実行してください。

    var stopWatch = new System.Diagnostics.Stopwatch();
    stopWatch.Start();

    string str = “a”;
    for (int i = 0; i < 100000; i++)
    {
    str += “b”;
    }

    stopWatch.Stop();

    Console.WriteLine(stopWatch.ElapsedMilliseconds + “ミリ秒”);

    +による文字列追加はとても遅い

    このサンプルは文字列の追加を10万回繰り返します。実行すると私の環境では6000ミリ秒ちょっとかかってしまいます。+で文字列を追加するのは簡単で便利ですが、処理がとても遅いのです。

    ではforループの箇所を以下のように変更しましょう。ソースの先頭には「using System.Text;」を追加してください。

    StringBuilder str = new StringBuilder(“a”);
    for (int i = 0; i < 100000; i++)
    {
    str.Append(“b”);
    }

    StringBuilderを使えば劇的に高速化できる

    これを実行すると、私の環境では約4ミリ秒で終わります。実に1500倍の高速化です。+の文字列追加は内部ではStringBuilderクラスのAppendを呼んでいるのですが、最初からそうしてあげるだけでこれほどの高速化ができるのです。

    これに近い最適化のテクニックとして、「ボックス化を使わない」というのもあります。以下のC#サンプルを見てください。

    var stopWatch = new System.Diagnostics.Stopwatch();
    stopWatch.Start();

    object num = 0;
    for (int i = 0; i < 1000000; i++)
    {
    num = i;
    }

    stopWatch.Stop();

    Console.WriteLine(stopWatch.ElapsedMilliseconds + “ミリ秒”);

    ボックス化は処理が遅い

    これを実行すると私のPC環境では30ミリ秒くらいかかります。このサンプルはobject型のnumにint型の値を代入しています。C#にはボックス化という機能があって、抽象的なobject型に数値を代入すると、数値を扱うクラスに変換してくれます。しかしこれはとても遅いのです。

    ではこのC#サンプルの、
    object num = 0;
    を、
    Int32 num = 0;
    に変えて実行してみましょう。

    無駄なnewは避けること

    結果は私のPC環境では4ミリ秒くらいになります。約8倍の高速化です。ボックス化の内部処理ではInt32型に変換しているのですが、それをこちらでやってあげればこんなに差が出るのです。

    C#に限らずオブジェクト指向言語で遅くなる原因の一つは「無駄にnewすること」です。+による文字列操作もボックス化も、内部でnewをしているため遅くなります。動的なnewを減らし、staticを多用して静的な設計にすると高速なプログラムになります。

    ただstaticを多用するとオブジェクト指向的ではない古臭いプログラムになってしまうのも事実で、エンジニアはそういったジレンマを考慮しつつバランスの良い設計を考える必要があります。

    システム
    エンジニア
    いろいろと工夫することで、C#の実行を高速化できるのですね。
    プロジェクト
    マネージャー
    紹介したテクニックを活用して、プログラムを記述してください。

    常に高速化を意識してC#プログラミングをしよう

    C#の最適化のテクニックを紹介しましたが、ご理解頂けましたでしょうか。

    コードをシンプルにしてくれる機能は、コンピュータにとっては負担になることがわかったと思います。常に高速化を意識してプログラムを記述するようにしましょう。

    FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
    株式会社オープンアップシステムロゴ

    株式会社オープンアップシステムはこんな会社です

    秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
    数多くのエンジニアが集まります。

    秋葉原オフィスイメージ
    • スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。

    • 充実した研修制度

      充実した研修制度

      毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。

    • 資格取得を応援

      資格取得を応援

      スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。

    • 東証プライム上場企業グループ

      東証プライム上場企業グループ

      オープンアップシステムは東証プライム上場「株式会社夢真ビーネックスグループ」のグループ企業です。

      安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。

    株式会社オープンアップシステムに興味を持った方へ

    株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。

    年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
    まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。

    株式会社オープンアップシステムへのご応募はこちら↓
    株式会社オープンアップシステムへのご応募はこちら↓

    C#新着案件New Job