Быстрый Array.Split
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 10.06.13 12:33
Оценка:
Уже задавал вопрос на StackOverflow, но тамошний коллективный разум ничего действенного не подсказал.

Дело вот в чем. Есть массив байтов (размер -- от нескольких байт до нескольких сотен килобайт). Нужно максимально быстро разбить его на куски. Критерий разбиения в моем случае -- по символу \n (0xA):

1, 2, 3, 10, 4, 10, 5, 6, 10, 7, 10 -> 1, 2, 3;  4;  5, 6;  7


По показаниям dotTrace:

"Наивная" версия -- 20 001 мс. на 2 312 вызовов:

public unsafe static Segment[] Split(this byte[] _src, byte value)
{
    var _ln = _src.Length;

    fixed(byte *src = _src)
    {
        if(_ln == 0) return new Segment[] { };

        var segments = new LinkedList<Segment>();// Segment[c];
        var l = 0;
        var j = 0;
        var last = 0;
        var i = 0;

        for(i = 0; i < _ln; i++)
        {
            l++;
            if(src[i] != value) continue;

            segments.AddLast(new Segment(_src, last, l));

            l = 0;
            last = i + 1;
        } // for

        if(last != i)
            segments.AddLast(new Segment(_src, last, _ln - last));

        return segments.ToArray();
    }
}


Оптимизация, предложенная Euphoric -- 4 696 мс на 2 312 вызовов:

public static unsafe Segment[] Split2(byte[] _src, byte value)
{
    var _ln = _src.Length;

    if (_ln == 0) return new Segment[] { };

    fixed (byte* src = _src)
    {
        var segments = new LinkedList<Segment>(); // Segment[c];

        byte* last = src;
        byte* end = src + _ln - 1;
        byte lastValue = *end;
        *end = value; // value-termination

        var cur = src;
        while (true)
        {
            if (*cur == value)
            {
                int begin = (int) (last - src);
                int length = (int) (cur - last + 1);
                segments.AddLast(new Segment(_src, begin, length));

                last = cur + 1;

                if (cur == end)
                {
                    if (lastValue != value)
                    {
                        *end = lastValue;
                    }
                    break;
                }
            }
            cur++;
        }

        return segments.ToArray();
    }
}


Почти в 5 раз быстрее, но все равно ужасно медленно.

Возможно, у вас будут какие-то предложения? Или переписать все на Managed C++ (или как там его нынче называют)?
HgLab: Mercurial Server and Repository Management for Windows
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.