私のC#アプリケーションのプロファイリングは、にかなりの時間が費やされていることを示しましたList<T>.AddRange
。Reflectorを使用してこのメソッドのコードを確認すると、List<T>.InsertRange
次のように実装されたコードが呼び出されることがわかりました。
public void InsertRange(int index, IEnumerable<T> collection)
{
if (collection == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
}
if (index > this._size)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
}
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
if (count > 0)
{
this.EnsureCapacity(this._size + count);
if (index < this._size)
{
Array.Copy(this._items, index, this._items, index + count, this._size - index);
}
if (this == is2)
{
Array.Copy(this._items, 0, this._items, index, index);
Array.Copy(this._items, (int) (index + count), this._items, (int) (index * 2), (int) (this._size - index));
}
else
{
T[] array = new T[count]; // (*)
is2.CopyTo(array, 0); // (*)
array.CopyTo(this._items, index); // (*)
}
this._size += count;
}
}
else
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Insert(index++, enumerator.Current);
}
}
}
this._version++;
}
private T[] _items;
インターフェイスの単純さ(InsertRangeのオーバーロードが1つしかない)は、ランタイムタイプのチェッキングとキャストのパフォーマンスオーバーヘッドを正当化すると主張することができます。しかし、私が示した3つの線の背後にある理由は何(*)
でしょうか?私はそれをより速い代替案に書き直すことができると思います:
is2.CopyTo(this._items, index);
この単純で明らかに高速な代替手段を使用しない理由はありますか?
編集:
答えてくれてありがとう。したがって、コンセンサスの意見は、これは、CopyToを欠陥のある/悪意のある方法で実装する入力コレクションに対する保護手段であるというものです。私には、1)ランタイムタイプチェック2)一時配列の動的割り当て3)コピー操作を2倍にするという代償を絶えず支払うのはやり過ぎのように思えますが、InsertRangeの2つ以上のオーバーロードを定義することでこれをすべて節約できたはずです、1つIEnumerable
は現在のように取得し、2つ目は取得しList<T>
、3つ目は取得しT[]
ます。後の2つは、現在の場合の2倍の速度で実行するように実装できます。
編集2:
T []引数を取るAddRangeのオーバーロードも提供することを除いて、Listと同じクラスFastListを実装しました。この過負荷は、動的な型の検証や要素の二重コピーを必要としません。最初は空だったリストに4バイト配列を1000回追加することにより、このFastList.AddRangeをList.AddRangeに対してプロファイリングしました。私の実装は、標準のList.AddRangeの速度を9倍(9!)で上回っています。List.AddRangeは、アプリケーションの重要な使用シナリオの1つでランタイムの約5%を占めます。リストを、より高速なAddRangeを提供するクラスに置き換えると、アプリケーションのランタイムが4%向上する可能性があります。