-1

LINQ が行うことを複製する Enumerable を実装しようとしてOrderByいました。そのために、次の 2 つの方法を使用しました。

  1. Mono の Linq/Enumerable.cs をベースとして使用し、OrderByコードを Enumerable に複製しました。
  2. 逆コンパイラを使用して .NET のバージョンの印象をつかみ、そのコードを複製しました。

LINQ バージョンと両方のオプションのベンチマークを行うと.Take(10)(以前は出力が少なかった)、linq バージョンは大幅に高速です (1900 ミリ秒と 3700 ミリ秒)。ソース データはList<MyObject>で、char メンバで並べ替えられました。最適化build flag was on

誰かがこの違いがどこから来るのか説明してもらえますか?

編集: 2. のコードの概要を以下に示します。

ここでBuffer<TElement>は、 のコピーSystem.Linq.Buffer<TElement>(ILSpy内部にあるため からコピー) であり、Sort(ほとんど) から同じ方法でコピーされSystem.Linq.EnumerableSorter<TElement>ます。

public class Query2F
{
    private Func<Lineitem, char> keySelector;
    private char[] keys;
    private IComparer<char> comparer;
    private bool descending;

    public Query2F(Func<Lineitem, char> keySelector, bool descending)
    {
        this.keySelector = keySelector;
        this.descending = descending;
        this.comparer = Comparer<char>.Default;
    }

    public static IEnumerable<Lineitem> Execute(List<Lineitem> lineitem)
    {
        Buffer<Lineitem> buffer = new Buffer<Lineitem>(lineitem);
        if (buffer.count > 0)
        {
            Query2F q2f = new Query2F((s => s.returnflag), false);
            int[] array = q2f.Sort(buffer.items, buffer.count);
            q2f = null;
            for (int i = 0; i < buffer.count; i++)
            {
                yield return buffer.items[array[i]];
            }
        }
        yield break;
    }

    private void ComputeKeys(Lineitem[] elements, int count)
    {
        this.keys = new char[count];
        for (int i = 0; i < count; i++)
        {
            //this.keys[i] = this.keySelector(elements[i]);
            this.keys[i] = elements[i].returnflag;
        }
    }

    private int CompareKeys(int index1, int index2)
    {
        int num = this.comparer.Compare(this.keys[index1], this.keys[index2]);
        if (num == 0)
        {
            return index1 - index2;
        }
        else
        {
            if (!this.descending)
            {
                return num;
            }
            return -num;
        }
    }

    internal int[] Sort(Lineitem[] elements, int count)
    {
        this.ComputeKeys(elements, count);
        int[] array = new int[count];
        for (int i = 0; i < count; i++)
        {
            array[i] = i;
        }
        this.QuickSort(array, 0, count - 1);
        return array;
    }

    private void QuickSort(int[] map, int left, int right)
    {
        do
        {
            int num = left;
            int num2 = right;
            int index = map[num + (num2 - num >> 1)];
            do
            {
                if (num < map.Length)
                {
                    if (this.CompareKeys(index, map[num]) > 0)
                    {
                        num++;
                        continue;
                    }
                }
                while (num2 >= 0 && this.CompareKeys(index, map[num2]) < 0)
                {
                    num2--;
                }
                if (num > num2)
                {
                    break;
                }
                if (num < num2)
                {
                    int num3 = map[num];
                    map[num] = map[num2];
                    map[num2] = num3;
                }
                num++;
                num2--;
            }
            while (num <= num2);
            if (num2 - left <= right - num)
            {
                if (left < num2)
                {
                    this.QuickSort(map, left, num2);
                }
                left = num;
            }
            else
            {
                if (num < right)
                {
                    this.QuickSort(map, num, right);
                }
                right = num2;
            }
        }
        while (left < right);
    }
}

internal struct Buffer<TElement>
{
    internal TElement[] items;
    internal int count;
    internal Buffer(IEnumerable<TElement> source)
    {
        TElement[] array = null;
        int num = 0;
        ICollection<TElement> collection = source as ICollection<TElement>;
        if (collection != null)
        {
            num = collection.Count;
            if (num > 0)
            {
                array = new TElement[num];
                collection.CopyTo(array, 0);
            }
        }
        else
        {
            foreach (TElement current in source)
            {
                if (array == null)
                {
                    array = new TElement[4];
                }
                else
                {
                    if (array.Length == num)
                    {
                        TElement[] array2 = new TElement[checked(num * 2)];
                        Array.Copy(array, 0, array2, 0, num);
                        array = array2;
                    }
                }
                array[num] = current;
                num++;
            }
        }
        this.items = array;
        this.count = num;
    }
    internal TElement[] ToArray()
    {
        if (this.count == 0)
        {
            return new TElement[0];
        }
        if (this.items.Length == this.count)
        {
            return this.items;
        }
        TElement[] array = new TElement[this.count];
        Array.Copy(this.items, 0, array, 0, this.count);
        return array;
    }
}
4

1 に答える 1

0

問題が解決しました。解決策を教えてくれたマイクに感謝します。

実行時間の不一致の理由は、単に間違ったビルド (リリース ビルドではない) を実行したためです。

于 2013-10-15T15:21:58.810 に答える