Re: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.09.06 17:23
Оценка: 10 (2)
Здравствуйте, Denis2005, Вы писали:

Ну, раз пошла такая пьянка грех не порекламировать Nemerle .

Вот написал это никчемный тестик. Причем разными спосбами чтобы оценить насколько дорого обходится функционалщина и другие хайтек-изыски в современных языках. Особенноп риятно этот тест сравнивать с вот этоим произведением человеческой мысли .

Сначала результатаы (AMD Атлон 64 3500 (2.2 Ггц):
[123, 345, asdf, 23453, asdfas]
00:00:00.8376620
5000000
00:00:00.2925531
5000000
00:00:00.7282637
5000000

Первый результат — это рукописный Split возвращающий (какой ужас!) динамический списко (то есть на каждый жлемент списка создается по дополнительному объекту с указателем на следующий элемент. Размет каждого доп. объекта 16 байт). Ко всему прочему этот метод строит прямой список для чего ему приходится использовать стек (не использовать концевую рекурсию). Так же для вычисления длинны списка свойство Length делет (ужас то какой!) еще один проход по списку.
Второй результат — это токенайзер возвращающий позицию токена. Интересен он тем, что использует конструкцию yield (то есть является континюэшоном).
Третий результат — это библиотечный метод Split().

А теперь код:
using System.Console;
using  System.Diagnostics.Stopwatch;

module Parse
{
  public Split(this str : string) : list[string]
  {
    def loop(start, i, lst)
    {
      if (i < str.Length)
        match (str[i])
        {
          | ' ' | '\t' => str.Substring(start, i - start) :: loop(i + 1, i + 1, lst)
          | _ => loop(start, i + 1, lst)
        }
      else if (start == i) lst
      else                 [str.Substring(start, i - start)];
    }

    loop(0, 0, []);
  }

  public Tokenize(this str : string) : System.Collections.Generic.IEnumerable[(int * int)]
  {
    def loop(start, i)
    {
      if (i < str.Length)
        match (str[i])
        {
          | ' ' | '\t' =>
            yield (start, i - start);
            loop(i + 1, i + 1)

          | _ => loop(start, i + 1)
        }
      else if (start != i) yield (start, i - start)
      else                 ()
    }

    loop(0, 0);
  }
}

////////////////////////// Далее идут тесты /////////////////////////////////

WriteLine(Parse.Split("123 345 asdf 23453 asdfas"));

/////////////////////////////////////////////////////////////////////////////
// Тестируем сплит написанный что называется в стиле "мама не горюй" (с динамическими списками).
def timer = StartNew();

mutable count = 0;
for(mutable i = 0; i < 1000000; ++i)
  count += Parse.Split("123 345 asdf 23453 asdfas").Length;

WriteLine(timer.Elapsed);
WriteLine(count);

/////////////////////////////////////////////////////////////////////////////
// Тестируем бибилиотечный сплит.
def timer = StartNew();

count = 0;
for(mutable i = 0; i < 1000000; ++i)
  foreach (_ in Parse.Tokenize("123 345 asdf 23453 asdfas"))
    count++;

WriteLine(timer.Elapsed);
WriteLine(count);

/////////////////////////////////////////////////////////////////////////////
// Тестируем токенайзер.
def timer = StartNew();

count = 0;
for(mutable i = 0; i < 1000000; ++i)
  count += "123 345 asdf 23453 asdfas".Split().Length;

WriteLine(timer.Elapsed);
WriteLine(count);

_ = ReadLine();
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.