А так же о всякой фигне
В этот раз посмотрим стандартную во всех языках функцию замены подстроки в строке. В php это str_replace, в javaScript str.replace, в python str.replace, и в lua str:gsub.
Почему именно эту функцию? А потому, что практически в любом веб-проекте используется какой-либо шаблонизатор, а уже шаблонизатор по сути занимается тем что в шаблоне (текстовая переменная) меняет определённые подстроки (ключи) на нужные данные. В простейшим виде, в шаблон вида:
<html> <body> <h1>{title}</h1> <div class="page-text">{text}</div> </body> </hrml>
Вместо меток {title} и {text}, подставляются данные из какой-либо СУБД(например mysql как в 90% субд на просторах интернетов). Конечно есть ещё способ не делать string replace, а исполнять код внутри шаблона, например так:
<?php // $title = ... // $text = ... ?> <html> <body> <h1><?php echo $title ?></h1> <div class="page-text"><?php echo $text ?></div> </body> </hrml>
И он будет работать на много быстрее шаблонизаторов. Но в современном веб-деве принято жестко отделять всю логику от шаблонов.
Исходники тестов:
<?php function getRandomChar() { $chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; return $chars{ rand(0, strlen($chars) - 1 ) }; } function createString($length) { $half = (int) $length / 2; $result = ''; for($i=0; $i<$half; $i++ ) { $result .= getRandomChar(); } $result .= '{REPLACE_ME}'; for($i=0; $i<$half; $i++ ) { $result .= getRandomChar(); } return $result; } function test($strLength, $count) { $startTime = microtime(true); echo "str_length=$strLength test_count=$count, start_time=$startTime"; $soutseString = createString($strLength); for($i=0; $i<$count; $i++) $res = str_replace('{REPLACE_ME}', '~TEST~', $soutseString); $worktime = microtime(true) - $startTime; echo " RESULT=$worktime "; } echo " ~ TEST ~ "; test(1000, 100000000); test(10000, 10000000); test(100000, 1000000); ?>
from random import randrange import time def getRandomChar(): chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890' return chars[ randrange(0, len(chars) - 1) ] def createString(length): result = '' half = (int)( length / 2 ) i = 0 while i < half: result += getRandomChar() i += 1 result += '{REPLACE_ME}' i = 0 while i < half: result += getRandomChar() i += 1 return result def test(strLength, count): startTime = time.time() print( "str_length=" + str(strLength) + ", test_count=" + str(count) + ", start_time=" + str(startTime) ) soutseString = createString(strLength) i = 0 while i < count: i += 1 res = soutseString.replace("{REPLACE_ME}", "~TEST~") worktime = time.time() - startTime print( "RESULT=" + str(worktime) ) test(1000, 100000000) test(10000, 10000000) test(100000, 1000000)
function getRandomChar() { let chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; return chars[ Math.floor(Math.random() * (chars.length-1)) ]; } function createString(length) { let half = parseInt( length / 2 ); let result = ''; for(let i=0; i<half; i++ ) { result += getRandomChar(); } result += '{REPLACE_ME}'; for(let i=0; i<half; i++ ) { result += getRandomChar(); } return result; } function test(strLength, count) { let startTime = Date.now(); console.log( `str_length=${strLength}, test_count=${count}, start_time= ${startTime}`); let soutseString = createString(strLength); let rep = new RegExp('{REPLACE_ME}', 'g'); for(i=0; i<count; i++) { let res = soutseString.replace(rep, '~TEST~'); } let worktime = Date.now() - startTime; console.log( `RESULT=${worktime / 1000}`); } console.log( ' ~TEST~' ); test(1000, 100000000); test(10000, 10000000); test(100000, 1000000);
function getRandomChar() local chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; local symbIndex = math.random(1,chars:len() ) return chars:sub(symbIndex, symbIndex) end function createString(length) local half = math.floor(length / 2) local result = '' for i = 1, half, 1 do result = result .. getRandomChar() end result = result .. '{REPLACE_ME}' for i = 1, half, 1 do result = result .. getRandomChar() end return result end function test(strLength, count) local startTime = os.clock(); print( 'str_length=' .. strLength .. ', test_count=' .. count .. ', start_time=' .. startTime); soutseString = createString(strLength) for i = 1, count, 1 do local res = soutseString:gsub('{REPLACE_ME}', '~TEST~') end local workTime = os.clock() - startTime; print( 'RESULT=' .. workTime ) end math.randomseed( os.time() ) test(1000, 100000000) test(10000, 10000000) test(100000, 1000000)
Для тестов как обычно используем 5-и долларовую виртуалку на линоде, версии софта: PHP: 7.0.30, Python: 3.5.3, Node.js: 10.6.0, Lua: 5.3.3, LuaJit: 2.0.4. За исключением ноды, весь софт из стандартного дистрибутива debian. Нода в стандартном дистре очень древняя, но у неё есть собственный репозиторий для всех видов линюксов, в отличии, например, от пхп.
str_length*test_count | 1000*100000000 | 10000*10000000 | 100000*1000000 |
---|---|---|---|
Node.js | 17.969s | 4.498s | 3.541s |
PHP | 20.4376s | 92.5527s | 87.6090s |
Python | 62.6877s | 23.4150s | 33.5308s |
LuaJIT | 1275.6611s | 1233.8939s | 1266.4118s |
Lua | 1304.2875s | 1276.2183s | 1272.9350s |
Значения указаны в секундах. Чем значение меньше, тем быстрее отработал скрипт, тем лучше.
Я не смог дождаться результатов от луа, скрипт после 15 минут так и не выдал даже первые данные, по этому, для луа, я уменьшил в 10 раз количество итераций, а результаты соответственно умножил на 10. Не помогла и Jit компиляция, именно в этом случае она вообще не дала никакого прироста в скорости.
Ну и нода , как обычно рулит, пхп и питон +- одинаковы, каждый в своей категории.
Как мы получали визу в Великобританию (2018 год)
Решили мы значит сгонять на месяцок в Англию, в Лондон этой осенью, захотелось нам хоть не на много почувствовать себя жителями нормальной страны.
Сравнение скорости работы nodejs, php, python, lua, luajit часть 3, сортировка массивов
В этой части будем тестировать сортировку числовых массивов. Node.js: array.sort(), PHP: sort(), Python: array.sort(), Lua: table.sort()