RDM/2 The Russian Electronic Developer Magazine  
RDM/2 Русский электронный журнал разработчика  
ДомойОт редактораПишите намОбратная связьRU/2

Object REXX. Есть ли смысл?

Некоторое время назад я обнаружил на сайте IBM новую версию ObjectREXX для Warp3, скачал и установил её. Вообще-то у меня Warp4Rus, но до FP5, как минимум, ObjREXX в мерлине не фиксился, а исправления ошибок и новых фич хочется всем. ;) Вот и в этой версии появились новые функции для работы с кортежами (stem). Описания не было, но после короткой переписки с разработчиками я его получил, перевёл и результат был опубликован здесь.

Меня заинтересовала функция 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 | Добавить комментарий
---
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов
(C) Russian Underground/2