Сравнение скорости работы nodejs, php, python, lua, luajit часть 2, string replace

В этот раз посмотрим стандартную во всех языках функцию замены подстроки в строке. В 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>

И он будет работать на много быстрее шаблонизаторов. Но в современном веб-деве принято жестко отделять всю логику от шаблонов.

Методика тестирования

  1. Создаём строку, в середину строки вставляем метку "{REPLACE_ME}"
  2. Ндцать раз заменяем "{REPLACE_ME}" на "~TEST~"
  3. Замеряем время

Исходники тестов:

PHP

<?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);

?>

Python

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)

JavaScritp/Node.js

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);

Lua/LuaJit

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()


(0) Комментариев