ネコのために鐘は鳴る

寺院に住み着くパソコ〇好き

2020-01-01から1年間の記事一覧

(C#) 3種類の定数と JIT コンパイル時最適化

この記事は「C# Advent Calendar 2020」の24日目の記事です。 3種類の定数と分岐削除 C# には3種類の定数があります。とはいえ、実際に C# のソースコードとして目に見えるのは1種類だけでconstとして書くものです。それぞれ順に見ていきましょう。 C#定数 (…

(C#) Fast Span と Slow Span の挙動の不一致の罠

System.Span<T> および System.ReadOnlySpan<T>はメモリの連続領域を表すための配列ライクなオブジェクトです。 配列T[]およびそのスライス、スタックメモリstackalloc T[]、ポインタ (マネージドとアンマネージドの両方)を統一的に扱える便利なものです。 これら</t></t>…

(C#) ランタイムが Blazor WebAssembly か否かを取得する

実行中のOS が何であるかを取得する時はSystem.Environment.OSVersion.Platformを使えそうかと思ってました。 using System; // Windows 10 なら "Win32NT" Console.WriteLine(Environment.OSVersion.Platform); ところが、これを Mac の .NET Core で取得す…

(C#) エンディアン固定でシリアライズ

今回のオチ System.Buffers.Binary.BinaryPrimitives クラスを使いましょう エンディアンを固定でシリアライズしたい longの値をbyte[]にしたい時、普通はSystem.BitConverter.GetBytes(long)で困らないんですが、BitConverterのエンディアンは固定じゃない…

(C#) static コンストラクタを手動で呼ぶ

方法だけ知りたい生き急いでいる人用 // using System.Runtime.CompilerServices; RuntimeHelpers.RunClassConstructor(typeof(Hoge).TypeHandle); 以下説明 static コンストラクタが呼ばれない状況 C# の構造体やクラスには、インスタンスのコンストラクタ…

(C#) ArrayPool<T>.Shared 解体新書

ArrayPool<T>.Shared みなさんはSystem.Buffers.ArrayPool<T>.Shared使ってますか?使ってない?なら使いましょう。 ArrayPool<T>.Sharedは短期間だけ利用するようなバッファを貸してくれるものです。 new T[N]と違い、一度使った配列を使いまわすことができるのでガ</t></t></t>…

(C#) #if DEBUG を使わないデバッグ分岐

デバッグとリリースで処理を変えたいときは普通は大体以下のように書きます。 public void Foo() { #if DEBUG Console.WriteLine("This is Debug."); #else Console.WriteLine("This is Release"); #endif } 正直見にくいです。コンパイルされない側の記述は…

Unity (.netstandard2.0) でSpan<T>を使う

Unity でAPIターゲットを.netstandard2.0にしてSpan<T>を使うときに必要なライブラリたち。 .net 4.x系をターゲットにしても使える気はする(が面倒なので確認していない)。まあ、多少依存関係が違うのでnugetのパッケージのdependencyを見て適当に必要なの持っ</t>…

(C#) メモリ確保ベンチマーク 6種盛り

バッファの確保用にnew byte[N]なんて書いたらモテませんよ。とはいえ正直確保するバイト数次第。ベンチマーク見ましょう。 メモリ確保 6種盛り メモリ確保(+破棄)の方法を6種用意した。 // (1) new byte[] MarshalAlloc() { return new byte[N]; } // (2) A…

(C#) Span<T> を List<T>.AddRange したい

タイトル通りですが本記事執筆時点 (2020/4/15) の最新である .NET Core 3.1 ではList<T>のAddRangeメソッドにダイレクトにSpan<T>およびReadOnlySpan<T>を突っ込むことはできません。というのもList<T>のAddRangeメソッドは public void AddRange(IEnumerable<T> items); </t></t></t></t></t>…

(C#) List<T>からSpan<T>を引き抜いて高速化

List<T>はGetEnumerator()を実装しているため当然foreachで回せる。foreachの速度を落とさないために具象型のEnumeratorを返したりEnumeratorを構造体実装していたりと工夫は凝らされているが、それでもSpan<T>やT[]には数倍~10倍程度遅い。この点に関しては、List<T></t></t></t>…

(C#) ラムダ式による this のキャプチャ

ラムダ式による外部変数のキャプチャは、コンパイラによって暗黙的に匿名クラスが作られ、コールされるたびに匿名クラスのインスタンスがnewされるため、ヒープアロケーションが発生する。 using System; public class Class { public Action Method(int num…

(雑記) int の範囲チェック速度 小ネタ

int型の整数の引数の範囲チェックで、0 から Size の範囲外だったら例外を投げる、のような範囲チェックはする機会が多いが、 int valueとint Sizeに対して if(value < 0 || value >= Size) throw new ArgumentOutOfRangeException(); よりも if((uint)value…

(C# 雑記) Linq の Count() と IReadOnlyCollection<T>

Linq のCount()、つまりint Enumerable.Count(IEnumerable<T>)は原理的には全列挙による数え上げだが、配列ライクなものは初めから要素数を持っているのでO(N)を回す必要はない。そのため、配列ライクなものについては直接要素数を取るよう最適化が施されている</t>…

(C#) 共変性による参照型配列のパフォーマンス

C# の配列は共変性 (covariance) があり、以下のコードはコンパイルできます。 object[] array = new int[10]; array[2] = 5; そして困ったことに、次のコードもコンパイルできます。 object[] array = new int[10]; array[2] = "hello"; // ← 代入できる!…

(C#) 参照型インスタンスのアドレスを取得する

C# では unsafe キーワードを使うことで値型のポインタや、unmanaged型配列の配列要素へのポインタを取得できますが、 参照型インスタンスへのポインタは取得できません。ガベージコレクション (GC) によるコンパクションでアドレスが移動する可能性があり、…

(雑記) xorshiftって0出ないよね

疑似乱数生成アルゴリズムの Xorshift を実装してみて思ったんですが、これって何回生成しても0は出てこないですよね。 Xorshift のアルゴリズムは元論文見るのが早いです。すごい短いし。解説サイトだとこのページが丁寧。 要約すると、32bit版はこれです。…

(C#) ReadOnlyCollection<T> を Unsafe.As で違法に書き換える

System.Runtime.CompilerServices.Unsafe クラス System.Runtime.CompilerServices.Unsafeクラスは C# において safe なコンテキストで unsafe なことができる、.NET の標準ライブラリにある公式黒魔術書です。Unsafeという名前から明らかですが、safe で使…

(C#) 配列の for の JIT 最適化処理

[前提] C# のコンパイルと JIT コンパイル C# --> [コンパイル] --> IL -> [JIT] --> バイナリ の流れを知ってる人は読み飛ばしてください forの最適化の話をする前に、C#のソースコードが実行可能バイナリ (アセンブリ) にコンパイルされるまでの流れをおさ…