Почему мой string.indexof (char) быстрее?

Не спрашивайте, как я туда попал, но я играл с маскировкой, разворачиванием цикла и т. д. В любом случае, из интереса я думал о том, как я буду реализовывать метод indexof и, короче говоря, все это маскирование и т. д. в стороне, эта наивная реализация:

public static unsafe int IndexOf16(string s, int startIndex, char c) {
            if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
            fixed (char* cs = s) {
                for (int i = startIndex; i < s.Length; i++) {
                    if ((cs[i]) == c) return i;
                }
                return -1;
            }
        }

быстрее, чем string.IndexOf (char). Я написал несколько простых тестов, и, похоже, результат точно соответствует. Некоторые примеры выходных чисел с моей машины (в какой-то степени, конечно, но тенденция очевидна):

short haystack 500k runs
1741 ms for IndexOf16
2737 ms for IndexOf32
2963 ms for IndexOf64
2337 ms for string.IndexOf <-- buildin

longer haystack:
2888 ms for IndexOf16
3028 ms for IndexOf32
2816 ms for IndexOf64
3353 ms for string.IndexOf <-- buildin

IndexOfChar помечен как extern, поэтому вы не можете его отразить. Однако я думаю, что это должна быть (нативная) реализация: http://www.koders.com/cpp/fidAB4768BA4DF45482A7A2AA6F39DE9C272B25B8FE.aspx?s=IndexOfChar#L1000

Кажется, они используют ту же наивную реализацию.

Мне приходят в голову вопросы:

1) Мне что-то не хватает в моей реализации, что объясняет, почему она быстрее? Я могу думать только о поддержке расширенных символов, но их реализация предполагает, что они также не делают ничего особенного для этого.

2) Я предполагал, что большая часть низкоуровневых методов в конечном итоге будет реализована на ручном ассемблере, что, похоже, не так . Если да, то зачем вообще реализовывать его изначально, а не только на C #, как в моем примере реализации?

(Полный тест здесь (думаю, его слишком долго вставлять сюда): http://paste2.org/p / 1606018 )

(Нет, это не преждевременная оптимизация, это не для проекта, над которым я просто балуюсь): -)

Обновление : Спасибо Оливеру за подсказку о нулевой проверке и счетчике парам. Я добавил их в свой IndexOf16Implementation следующим образом:

public static unsafe int IndexOf16(string s, int startIndex, char c, int count = -1) {
    if (s == null) throw new ArgumentNullException("s");
    if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
    if (count == -1) count = s.Length - startIndex;
    if (count < 0 || count > s.Length - startIndex) throw new ArgumentOutOfRangeException("count");

    int endIndex = startIndex + count;
    fixed (char* cs = s) {
        for (int i = startIndex; i < endIndex; i++) {
            if ((cs[i]) == c) return i;
        }
        return -1;
    }
}

Числа немного изменились, но все еще значительно быстрее (32/64 результаты опущены):

short haystack 500k runs
1908 ms for IndexOf16
2361 ms for string.IndexOf
longer haystack:
3061 ms for IndexOf16
3391 ms for string.IndexOf

Update2 :Эта версия еще быстрее (особенно для случая длинного стога сена):

public static unsafe int IndexOf16(string s, int startIndex, char c, int count = -1) {
            if (s == null) throw new ArgumentNullException("s");
            if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
            if (count == -1) count = s.Length - startIndex;
            if (count < 0 || count > s.Length - startIndex) throw new ArgumentOutOfRangeException("count");

            int endIndex = startIndex + count;
            fixed (char* cs = s) {
                char* cp = cs + startIndex;
                for (int i = startIndex; i <= endIndex; i++, cp++) {
                    if (*cp == c) return i;
                }
                return -1;
            }
        }

Обновление 4: Основываясь на обсуждении с LastCoder, я считаю, что это зависит от архитектуры. Мой Xeon W3550 на работе, похоже, предпочитает эту версию, а его i7, похоже, нравится встроенная версия. Моя домашняя машина (Athlon II) оказалась где-то посередине. Однако меня удивляет большая разница.

16
задан chrisaut 24 August 2011 в 18:50
поделиться