Что нового

Сравнение скорости AutoIt VS Perl

Suppir

Продвинутый
Сообщения
967
Репутация
62
Заметил, что AutoIt очень медленно читает и записывает файлы построчно. См. код:

Код:
#include <Timers.au3>
Global $starttime = _Timer_Init()
Global $OUT = FileOpen("test.txt", 2)

For $x = 1 to 1000000 Step 1
	FileWriteLine($OUT, "Some text 1234567890")

Next
MsgBox(0, "", _Timer_Diff($starttime))


На моем Pentium E5300 время исполнения около 9 секунд.


Тот же самый код на Perl:

Код:
use Benchmark;

open (OU, ">test.txt");
$t0 = new Benchmark;
for (1 .. 1000000){
	print OU "Some text 1234567890\n"
}

$t1 = new Benchmark;
$td = timediff($t1, $t0);
print "the code took:",timestr($td),"\n";
<>

Время исполнения 0,3 секунды! Т.е. в 30 раз быстрее!

При чтении файла разрыв примерно в 10 раз.

Я пришел к выводу, что в AutoIt плохо реализована буферизация STDIN/STDOUT. При каждом вызове функции FileWriteLine() или FileReadLine() AutoIt делает запись на диск. В то время как Perl читает и пишет "порциями".

Таким образом, чтобы повысить скорость чтения(для записи не работает) с диска с помощью AutoIt, нужно не использовать эту функцию в цикле, а по возможности считывать весь файл в одну переменную. В таком случае скорость будет выше.


Добавлено:
Сообщение автоматически объединено:

*Можно, конечно, сказать, что модуль Timers замедляет работу, но в Perl также используется модуль bechmark, так что разница нивелируется.*


Добавлено:
Сообщение автоматически объединено:

Кто придумает, как записать в файл 1 миллион раз строку

Some text 1234567890

менее чем за три секунды, то поделитесь рецептом! У меня не получается.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Не знаю как на E5300, но у меня ~3.5 секунды работает ваш код. ;)
Проверил на PHP, результат 11 сек.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
А что у вас за машина?

У меня 2 серверных приложения на машине работают. Но, в любом случае, условия для двух скриптов были полностью аналогичными.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
У меня старенький ноутбук Samsung P29, 1,40 ГГц, 896 МБ ОЗУ результат 5266.54169733863.
Меня такая скорость вполне устраивает.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Suppir сказал(а):
А что у вас за машина?

У меня 2 серверных приложения на машине работают. Но, в любом случае, условия для двух скриптов были полностью аналогичными.

У меня P4 3GHz Socket 478 ОЗУ 1,5 ;)
 

Guezt

Продвинутый
Сообщения
335
Репутация
82
Обязательно что бы сразу в файл писалось?! а как на счет записи строки из памяти раз в 1-2 секунды раз такая скорость нужна.
Код:
#include <Timers.au3>
Global $starttime = _Timer_Init()
Global $OUT = FileOpen("test.txt", 2)
$sBuf="Some text 1234567890"&@CRLF

For $x = 1 to 1000000
	$sBuf+=$sBuf
    ;FileWriteLine($OUT, "Some text 1234567890")
Next
FileWrite($OUT,$sBuf)
MsgBox(0, "", _Timer_Diff($starttime))
:-\
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Guezt [?]
а как на счет записи строки из памяти раз в 1-2 секунды раз такая скорость нужна.
мм.. а где в твоем коде реализация твоих слов? ;D
самый надежный вариант - записать все в переменную и записать в конце скопом. но на моей тачке это быстрее чем за 4.5 сек не получилось. против 0.3 сек на перле
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Попробовал на домашнем компе (Celeron 420, 1 Gb ram, винчестер 500 Gb)
AutoIt - 3,3 сек
Perl - 0,3 сек
Вариант, предложенный Guezt - 0,6 сек.

Как уже было замечено ранее и подтвержено вариантом Guezt, чтение/запись файла "за один проход" улучшают скорость AutoIt.
Однако при этом затруднена полноценная обработка строк - для того, чтобы работать с отдельными строками как с элементами, их все равно придется разделять с помощью StringSplit(), что еще сильнее замедляет работу.

Мне кажется, нужно написать в поддержку AutoIt, чтобы они пофиксили работу с чтением/записью файлов по строкам. Нужен человек, хорошо владеющий английским :smile:
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
При записи файла "скопом" будут следующие проблемы:
1) огромная переменная хранится в оперативной памяти. Не знаю, какой предел памяти на переменную в AutoIt, но мне часто приходится работать с файлами более 100 Гб.
2) при каком-то сбое в программе (например, произошло зацикливание в результате ошибки), оперативная память просто забьется и система повиснет.
3) не видно результатов работы программы. Некоторые скрипты работают по полчаса. При этом можно заглянуть в файл, который пишется и посмотреть, все ли идет правильно. А если писать скопом, AutoIt где-то в памяти будет крутить данные, а потом выдаст результат. Или не выдаст. В общем, узнать можно только через полчаса.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Guezt [?]
а разве не это я сделал?
да, это. не дочитал до конца. просто не увидел в коде запись с задержкой, вот и написал ;D
кстати, правильнее будет
Код:
$sBuf &= $sBuf

нежели чем
Код:
$sBuf += $sBuf



Добавлено:
Сообщение автоматически объединено:

еще одно наблюдение, если задать CRLF в самой строке а потом конкатенировать ее в цикле на моей машине скрипт обрабатывает за 1.5 сек. а если взять за строку первоначальный, а CRLF добавлять в цикле в конце каждой строки, то 4.5 сек.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Kaster, если написать $sBuf &= $sBuf
то скрипт выдает ошибку "error allocation memory"
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Suppir [?]
Kaster, если написать $sBuf &= $sBufто скрипт выдает ошибку "error allocation memory"
точно. я ведь не так делал. вот у меня ошибки то и не было.
если писать
Код:
$sBuf  &= $sBuf

то строка будет расти в геометрической прогрессии. конечно никакой памяти не хватет. а вот если делать так
Код:
$s = ''
For $x = 1 to 1000000
    $s &= $str
Next

то все норм
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Код:
#include <Timers.au3>
Global $starttime = _Timer_Init()
Global $OUT = FileOpen("test.txt", 2)
$str="Some text 1234567890"&@CRLF

$s = ''
For $x = 1 to 1000000
    $s &= $str
    ;FileWriteLine($OUT, "Some text 1234567890")
Next
FileWrite($OUT,$s)
MsgBox(0, "", _Timer_Diff($starttime))


Вот такой код 1,5 секунды у меня


Добавлено:
Сообщение автоматически объединено:

Даже при всех ухищрениях получается в 4 - 5 раз медленней, чем код Perl (который я не оптимизировал вообще):(
Нужно обратить внимание разработчиков. У Perl полностью открытый код - можно там подсмотреть реализацию и сделать также в AutoIt.
 

Guezt

Продвинутый
Сообщения
335
Репутация
82
Suppir
А не проще ли тебе проверять строку или они все будут разными ? и при условии записывать в файл ты бы объяснил, что ты хочешь обрабатывать, может совсем другим путём можно решить. :smile:
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Guezt, конечно, все будут разными.

Для разных случаев можно много способов оптимизации придумать, но хочется, чтобы в среднем работало быстрей.


Добавлено:
Сообщение автоматически объединено:

Ну, вот, например, я хотел перевести на AutoIt свой старенький скрипт для поиска специфических ошибок (пардоньте за неавтоитовский код):

Код:
# алфавит
$r = "[йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ]";
$l = "[qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM]";
$br = "[ЙЦУКЕНГШЩЗХЫВАПРОЛДЖЭЯЧСМИТЬБЮ]";
$lr = "[йцукенгшщзхъфывапролджэячсмитьбю]";

# подсчет ошибок и вывод в LOG
sub e{
	$e++;
	$err{$_[0]}=$_;
	$errnum{$_[0]}++;
	print "x";
	print LOG "$top, $_[0]:\n	$_\n\n";
	next}
	
# основой скрипт
open(LOG, ">$0.log");
while(<*.nsr>){
	open(IN,"$_");

	while(<IN>){

		e "спаренные кавычки" if /""/;
		e "три апострофа" if /'''/; 
		e "смесь апострофов и кавычек "if /"'|'"/;
		e "нетипичный апостроф" if /[^'\d]'[^s]/ && !/О'|Д'|точк|TCO/;
		e "нетипичная кавычка" if /\d["]\d/;
		e "сдвоенные знаки препинания" if /,[,.]/ && !/,\.{3}/;
		e "запятая не отделена пробелом" if /$r\s*,+$r/ && !/│/;
		e "знак препинания отделен от слова" if /^$r.+\s[,.:;!?](?!\.\.)/ && !/__|\d\s+:\s+\d/ && !/:/;
		e "нет пробела после номера пункта (или неверно распознана цифра)" if /^\s*\d+\.$r/;
		e "цифровой ряд не разделен пробелами" if /\d+,\d+,\d/;
		e "в ряде цифр пропущена запятая" if /\d\s+\d/ && !/|\d[,-:\.]\d|-го/ && /\d+,\s+\d+,/;
		e "строка содержит повторяющиеся слова" if /\s($r+)\s{1,7}\1\s/g && /$r{5,}/ && !/\s{9}/;
		e "диапазон дат записан через дефис" if /\D\d{4}-\d{4}\D/ && !/ГОСТ|│/;
		e "год не отделен от цифры" if /\d{4}г./ && !/│/;
		e "не проставлена ссылка на сайт" if /\s(http:\/\/)?www\./ && /$r{2,} /&& !/сайт/;
		e "ошибка в диапазоне чисел" if /\d\s+-\d|\d-\s+\d/ && !/"/;
		e "склеенный номер" if /\sN\d+/;
		e "неверная запись суммы" if /(тыс|млн|млрд)\.р/ && !/│/;;
		e "ошибка в сокращениях" if !/│/ && /(г|ул|р-н)\.$br$lr|(^| )(п|ст|гл)\.(\d)/; 
		e "инициалы написаны слитно" if !/__|│|подпись/ && /$br\.$br\.$br$lr+/;
		e "ошибка форматирования в таблице" if /│\s*[,;:\.]/ & !/\.\.\./;

}close IN}

# вывод статистики ошибок
if ($e){

	print LOG $/."СТАТИСТИКА ОШИБОК:$/"."="x18 .$/.$/;
	while (($key, $value) = each %errnum) {print LOG "$key - $value шт.\n"}	
	print LOG "\n\nИТОГО - $e шт."}
else {print LOG "ошибок не найдено"}
close LOG

Здесь придется читать файл построчно по двум причинам:
1) БД в несколько гигабайт не поместится в память
2) исполнять такое количество регулярных выражений на очень длинной переменной - сумасшествие. Поиск просто никогда не закончится.

Т.е. все равно придется читать построчно.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir

На мой взгляд, это вообще некорректное сравнение. FileWriteLine() и print() совершенно разного класса функции. FileWriteLine() работает непосредственно с системными функциями, а print() использует специальный буфер данных. В AutoIt буферизированной записи/чтения не реализованно. Если уж и сравнивать AutoIt и Perl, то по функциям FileWriteLine() и syswrite(). Интресно, кто здесь победит?
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied, мне не важно кто победит, я просто хочу заставить работать AutoIt быстрее. Если буферизация не реализована, ее просто необходимо сделать!
(по крайней мере, для меня это критично...)
 

bic

Знающий
Сообщения
46
Репутация
14
Код autoit из первого поста отрабатывает за 2.07 секунды.
CPU amd 5400, причем задействуется только одно ядро из двух. Нормальная скорость.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
В принципе, от CPU это мало зависит (больше от скорости винчестера).
Скорость нормальная для записи ini-файлов и т.п. Но для больших объемов информации скорость очень медленная. В идеале скорость записи должна приближаться к скорости записи, поддерживаемой винчестером.
 
Верх