32

C#で2バイト配列を追加するための最良の(以下を参照)方法はありますか?

完全に制御できるふりをして、最初のバイト配列を十分に大きくして、最後に2番目のバイト配列を保持し、Array.CopyTo関数を使用できます。または、個々のバイトをループして割り当てを行うこともできます。

より良い方法はありますか?バイト配列を文字列に変換して結合し、それらを元に戻すようなことを行うことは、上記のどちらの方法よりも優れているとは想像できません。

最高/より良い(順番に)に関して:

  1. 最速
  2. 最小のRAM消費

制約は、.NET2.0フレームワークで作業する必要があるということです。

推奨される2つの選択肢は、MemoryStreamとBlockCopyです。10,000,000ループの簡単な速度テストを3回実行したところ、次の結果が得られました。

ミリ秒単位での10,000,000ループの平均3回の実行:

  • BlockCopy時間:1154、範囲は13ミリ秒
  • MemoryStream GetBuffer時間:1470、範囲は14ミリ秒
  • MemoryStream ToArray時間:1895、範囲は3ミリ秒
  • CopyTo時間:2079、範囲は19ミリ秒
  • バイトごとの時間:2203、範囲は10ミリ秒

1000万ループを超えるList<byte> AddRangeの結果:List <byte>時間:16694

相対RAM消費量(1はベースライン、高いほど悪い):

  • バイトごと:1
  • BlockCopy:1
  • コピー先:1
  • MemoryStream GetBuffer:2.3
  • MemoryStream ToArray:3.3
  • リスト<バイト>:4.2

テストは、一般に、バイトコピーを大量に実行している場合を除いて、バイトコピー確認することは、焦点を当てる価値がないことを示しています[たとえば、1,000万回の実行で1.1秒の差が生じます]。

4

8 に答える 8

26

BlockCopyが必要

このブログ投稿によると、Array.CopyToよりも高速です。

于 2009-05-21T21:11:00.387 に答える
16

また、MemoryStreamを使用したアプローチを使用することもできます。b1とb2が2バイトの配列であるとすると、次の方法でMemoryStreamを使用することにより、新しい配列b3を取得できます。

var s = new MemoryStream();
s.Write(b1, 0, b1.Length);
s.Write(b2, 0, b2.Length);
var b3 = s.ToArray();

これはLINQがなくても機能するはずであり、実際にはかなり高速です。

于 2009-05-21T21:29:59.477 に答える
11

コンストラクターに、マージされたバッファーとまったく同じサイズのバッファーを渡す新しいMemoryStreamを作成します。個々の配列を記述し、最後にバッファを使用します。

byte[] deadBeef = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF};
byte[] baadF00d = new byte[] { 0xBA, 0xAD, 0xF0, 0x0D};
int newSize = deadBeef.Length + baadF00d.Length;
var ms = new MemoryStream(new byte[newSize], 0, newSize, true, true);
ms.Write(deadBeef, 0, deadBeef.Length);
ms.Write(baadF00d, 0, baadF00d.Length);
byte[] merged = ms.GetBuffer();

.NETの低レベルI/O関数の多くは、バイト配列とオフセットを取ります。これは、不必要なコピーを防ぐために行われました。パフォーマンスに敏感な場合は、マージされた配列が本当に必要であることを確認してください。それ以外の場合は、バッファーとオフセットを使用してください。

于 2009-05-21T21:18:36.957 に答える
7

別のオプションは、速度とメモリ消費の観点からどのように機能するかを確認するためにテストしていませんが、LINQアプローチでは次のようになります。

byte[] combined = bytesOne.Concat(bytesTwo).Concat(bytesThree).ToArray();

...ここで、bytesOne、bytesTwo、およびbytesThreeはバイト配列です。Concatは遅延実行を使用するため、中間配列を作成することはできません。また、最後にマージされた最終的な配列を作成するまで、元の配列を複製しないでください。

編集:LINQBridgeを使用すると、2.0フレームワークでLINQ-to-Objects(これは例です)を使用できます。これに依存したくないかどうかはわかりますが、それはオプションです。

于 2009-05-21T21:11:37.483 に答える
4

List<T>サイズが時々変化する配列がある場合は、そもそもを使用したほうがよいでしょう。AddRange()次に、リストのメソッドを呼び出すだけです。

それ以外の場合、Array.Copy()またはArray.CopyTo()は、他のどのようなものよりも優れています。

于 2009-05-21T21:05:55.437 に答える
3

配列の代わりにListまたはArrayListを使用することについて教えましたか?これらのタイプを使用すると、InsertRangeを介して拡大または縮小および追加できます。

于 2009-05-21T21:13:59.727 に答える
3

出力を実際にバイト配列にする必要がありますか?

そうでない場合は、自分で「スマートカーソル」を作成できます(これはLINQの機能に似ています)。最初に最初の配列を反復し、中断することなく2番目の配列を続行するカスタムIEnumerator<byte>を作成します。

これは2.0フレームワークで高速に機能し(アレイの結合に実質的にコストがかからないという点で)、アレイがすでに消費しているよりも多くのRAMを使用しません。

于 2009-05-21T21:22:14.547 に答える
1

最初の配列を2番目の配列を含むのに十分な大きさにし、Array.CopyToを使用する最初のオプションは、各アイテムを手動で繰り返して割り当てを行うのとほぼ同じになります。Array.CopyTo()は、それをより簡潔にします。

上記とは対照的に、文字列への変換と配列への変換は非常に遅くなります。そして、おそらくより多くのメモリを使用するでしょう。

于 2009-05-21T21:03:17.783 に答える