Как стать автором
Обновить

Комментарии 19

Может всё-таки генератор случайных…?
Тогда уж псевдослучайных.
Для генерации случайных строк точного размера из строго определённого набора символов я пользовался такой штукой:
function randomSymbol(symbols) {
  return symbols.substr(Math.random()*symbols.length, 1);
}

function randomString(sample, symbols) {
  return sample.replace(/ /g, function () {
    return randomSymbol(symbols);
  });
}

console.log(randomString('          ', '12345'));

Скорость пропорциональна длине генерируемой строки, почти не зависит от набора символов. Для строк из 10 символов примерно в 5 раза медленнее, чем у простого toString(36), что вполне достаточно для тестов. На nodejs 0.10.17 c2d 1.8 в среднем 3500 мс против 660 мс на миллионе вызовов.
Я не рекомендую этот способ, если кто не так понял, а добавляю в копилку тестов по поводу производительности регулярных выражений в подобного рода генераторах, для частного случая посимвольного глобального реплейса с калбэком. 300 тысяч циклов по 10 символов проходят в среднем за секунду, что примерно вдвое медленнее для v8, чем описанные результаты 4, 5.
Думаю, что минусы за странный избыточный код. Я сам удержался, чтобы не написать замечание и не начать спорить: ). 1) не видно оснований проходить цикл по образцу реплейсом — от этого и тормоза; не знаю, быстрее ли charAt(Math.random()*symbols.length), но аргументов на 1 меньше; 3) каждый раз извлекается symbols.length и двойной вызов функций.
А в плане приведения примера — очень положительно для комментария. Во всяком случае, ценнее замечаний по стилистике текстов.
Ага, понятно в чем дело, я бы тоже так подумал при первом взгляде. Но тут дело в том, что некоторые выводы не очевидны.
1) Откуда мысль о том, что проход шаблона реплейсом должен быть обязательно тормозным? Регулярки — весьма быстрая компилируемая штука, их скорость зависит в основном от логики. С другой стороны, циклы тоже хорошо оптимизируются. На деле charAt действительно оказывается быстрее, но не на порядки.
2) Передача параметров в тестах оказалась быстрее, чем обращение к ним по замыканию.
3) Извлечение length — крайне быстрая операция, это простое обращение к переменной, а не вычисление длины null-terminated строки.
4) Вынос вложенных функций за пределы не дал никакого прироста производительности, компилятор оказался не настолько глуп.
1) Откуда мысль о том, что проход шаблона реплейсом должен быть обязательно тормозным?
Из моих же свежих измерений из статьи. Нет, они, конечно, очень быстрые, особенно, в Хроме (сравните [4] и [5])? но в 2 раза медленнее цикла в Хроме, до 2.5 медленнее в сравнении с циклом — в IE. Остальные 2 фактора — они да, не такие существенные.
2) Передача параметров
Так лучше вообще 1 функцией обойтись — и передачи не будет.
3) Извлечение length
фактор маленький, но в общей функции его можно вынести за цикл. В двух — видимо, никак, разве что аргументом передавать.
Можно и одной, если первая не нужна в другом месте. По поводу length — у меня на тестах фактор отрицательный, например по этому jsperf.com/fastest-array-loops-in-javascript/56 быстрее всего работает for (var i = 0; i < arr.length; i++). Почему он должен быть быстрее, если length — это простое свойство у объекта, обращение к свойству медленнее, чем к аргументу функции?
Вот еще тест с пустыми телами цикла, без кеширования работает быстрее (на v8)
jsperf.com/browser-diet-cache-array-length
В целом, единственная настоящая проблема того решения — это то, что пробег по строке в регулярке работатет вдвое медленнее, чем посимвольно в цикле, с этим согласен.
Стало интересно, написал тест для конкретного случая взятия длины из строки и из замыкания. Как видно, зависимость весьма незначительная и непредсказуемая, и производительность больше зависит от версии v8 и платформы, чем от способа обращения к переменной. Результаты для разных браузеров не рассматриваю в контексте описанного случая (серверный js). Наверняка будут другие результаты, особенно для ие.
jsperf.com/length-in-functioin-params
>Math.random().toString(36).length
18
>Math.random().toString(35).length
1101
>Math.random().toString(34).length
34
>Math.random().toString(33).length
1101
>Math.random().toString(32).length
8
>Math.random().toString(31).length
1101

Почему такая разница в длине получаемых строк?
Потому что числа каждый раз разные.

x = Math.random()
x.toString(36).length
x.toString(35).length
...
// ну, вы поняли

Тем ни менее
>x = Math.random()
>x.toString(36).length
18
>x.toString(35).length
1101
Исходное число двоично-рациональное, вероятно, с 34 битами. Если основание системы счисления делится на два, число можно точно записать за 34 цифры, если на 4 — за 17 и т.д… Если основание нечетное, точно записать нельзя, и система дает столько знаков, сколько может.
Про чётное и нечётное основание понял, спасибо.
А где это такое? У меня в опере 12 win
javascript: Math.random().toString(35).length //14
javascript: Math.random().toString(31).length //13

1101 — это 13 в двоичном виде. Как оно получилось?
Chrome/30.0.1599.69, выполнял в консоли JS.
Сейчас выполнил в Хромиуме v.30 — действительно, более чем 1000-значная строка, .length не врёт. А Math.random().toString(32) вообще почему-то 7 знаков после точки
Math.random().toString(32)
"0.57ksc6g"
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории