The Russian Electronic Developer Magazine | |
Русский электронный журнал разработчика | |
Меня заинтересовала функция SysStemSort(), и было решено написать два ("классический" и "объектный") варианта скриптов сортировки. Принцип прост: читаем стандартный ввод в кортеж, кортеж сортируется, результат пишется на стандартный вывод. И никаких продвинутых "многопутевых слияний" ;)
Сразу скажу, что победило OO и с большим отрывом. Причина проста. Классика требует построчного ввода/вывода. В объектном есть ввод/вывод массивов (arrayin/arrayout). И хотя мне требовалось переносить строки между массивом и кортежем, суммарное время оказалось в разы меньше, чем при построчном вводе/выводе.
Вторая причина - наследование. Поскольку я писал скрипты-"пузомерки", требовалось как-то фиксировать достижения. Была сделана запись о трёх фазах (чтение/сортировка/запись) в лог-файл. ОО-вариант проще в использовании и с лёгкостью может быть применён в другом скрипте. Ещё одно достоинство: лог-файл открывается явно, без буферизации и в разделяемом режиме (Deny Write), поэтому закрываться должен явно. Реализация класса logger гарантирует закрытие файла даже при аварийном завершении скрипта.
Начнём с классического варианта. Здесь ничего необычного:
[RxSortC.cmd] /* Sample of use SysStemSort() from ObjectREXX RexxUtil version from 18/05/1999 */ if RxFuncQuery(SysStemSort) then if RxFuncAdd(SysStemSort,RexxUtil)\=0 then do call lineout con,"Can't register SysStemSort -", "check RexxUtil version" exit 1 end time=time(s) parse version name version day month year call wlog 'Log started by' name version '('day month year')' call time r buffer.0=0 do i=1 while chars()\=0 buffer.i=linein() buffer.0=i end call wlog ' ' buffer.0 'lines reading in', format(time(r),5,2)'s' if buffer.0>0 then if SysStemSort('buffer.')=0 then call wlog ' ' buffer.0 'lines sorting in', format(time(r),5,2)'s' else do call lineout con,'Error while sorting!' call wlog '!Error while sorting' buffer.0 'lines' end else call lineout con,'Nothing to sort' do i=1 to buffer.0 call lineout,buffer.i end call wlog ' ' buffer.0 'lines writing in', format(time(r),5,2)'s' drop buffer. call wlog 'Log ended, total time:' time(,time(s)-time,s) call RxFuncDrop SysStemSort exit 0 wlog: procedure return lineout('RxSortC.log',, left(date(s),4)right(date(o),6), time() '-', arg(1), )Всё просто, ничего необычного и вот результат (лучший из трёх):
1999/08/30 21:15:10 - Log started by OBJREXX 6.00 (18 May 1999) 1999/08/30 21:15:57 - 12883 lines reading in 47.27s 1999/08/30 21:16:12 - 12883 lines sorting in 15.27s 1999/08/30 21:16:21 - 12883 lines writing in 8.59s 1999/08/30 21:16:21 - Log ended, total time: 00:01:11Разница между лучшим и худшим результатом - 3 сек.
А теперь объектно-ориентированный вариант. Сначала класс logger:
[RxLog.cmd] /* Общедоступный класс для лог-файлов */ ::class logger public subclass stream ::method init -- Автоматически вызывается new() expose time time=time(s) -- time доступна всем методам объекта parse version name version day month year self~init:super(arg(1)) self~open(write append shareread nobuffer) self~lineout('Log started by' name version '('day month year')') ::method uninit -- Вызывается при drop и завершении скрипта expose time self~lineout('Log ended, total time:' time(,time(s)-time,s)) self~close self~uninit:super ::method lineout -- проставляем времЕнную отметку self~lineout:super(date(s,,,'/') time() '-' arg(1)) ::method warning -- просто строку в stderr .error~lineout:super(arg(1))Cобственно скрипт сортировки
[RxSortO.cmd] /* OO version of RxSortC sript */ if RxFuncQuery(SysStemSort) then if RxFuncAdd(SysStemSort,RexxUtil)=\0 then do .error~lineout("Can't register SysStemSort -", "check RexxUtil version!") exit 1 end log=.logger~new('RxSortO.log') call time r buffer.=.stem~new -- создаём объект-кортеж buffer=.array~new -- создаём объект-массив buffer=.input~arrayin -- вот и весь ввод;) buffer.0=buffer~items do i=1 to buffer.0 -- цикл для "переноски" строк buffer.i=buffer[i] end drop buffer -- освобождаем память log~lineout(' ' buffer.0 'lines reading in', format(time(r),5,2)'s') if buffer.0>0 then if SysStemSort('buffer.')=0 then log~lineout(' ' buffer.0 'lines sorting in', format(time(r),5,2)'s') else do log~warning('Error while sorting!') log~lineout('!Error while sorting' buffer.0 'lines') end else log~warning('Nothing to sort!') buffer=.array~new(buffer.0) -- создать массив известного размера do i=1 to buffer.0 buffer[i]=buffer.i end drop buffer.; buffer.0=buffer~items .output~arrayout(buffer) drop buffer log~lineout(' ' buffer.0 'lines writing in', format(time(r),5,2)'s') call RxFuncDrop SysStemSort ::requires RxLogА вот и результат (худший из трёх):
1999/08/30 21:17:16 - Log started by OBJREXX 6.00 (18 May 1999) 1999/08/30 21:17:22 - 12883 lines reading in 6.37s 1999/08/30 21:17:31 - 12883 lines sorting in 8.86s 1999/08/30 21:17:34 - 12883 lines writing in 2.66s 1999/08/30 21:17:34 - Log ended, total time: 00:00:18Разница лучший/худший - одна секунда.
Как можно видеть, меньшее время требуется не только на ввод/вывод, но и на сортировку. Объяснения этому факту у меня нет, но разница устойчивая. Тестировалось всё это на AMD-K6-2/300/64Mb.
В общем, ObjectREXX мне нравится. На очереди освоение start/reply/guard -- основы для написания многопоточных скриптов и скриптов-демонов.
Василий Сидоров.Примечание: для переключения между обычной и объектной версиями REXX используйте команду SWITCHRX
Интересные ссылки:
Комментариев к странице: 0 | Добавить комментарий
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов