Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

2.1.9. Эффективность вызововfdread иfdwrite

Процедура copyfile дает возможность оценить эффективность примитивов доступа к файлам в зависимости от размера буфера. Один из методов заключается просто в компиляции copyfile с различными значениями BUFSIZE, а затем в измерении времени ее выполнения при помощи команды UNIX time. Мы сделали это, используя программу

(* Программа для тестирования функции copyfile *)

begin

copyfile('test.in', 'test.out');

end.

и получили при копировании одного и того же большого файла (68307 байт) на компьютере с системой SVR4 UNIX для диска, разбитого на блоки по 512 байт, результаты, приведенные в табл. 2.2.

Таблица 2.2. Результаты тестирования функции copyfile

BUFSIZE

Real time

User time

System time

1

0:24.49

0:3.13

0:21.16

64

0:0.46

0:0.12

0:0.33

512

0:0.12

0:0.02

0:0.08

4096

0:0.07

0:0.00

0:0.05

8192

0:0.07

0:0.01

0:0.05

Формат данных в таблице отражает вывод команды time. В первом столбце приведены значения BUFSIZE, во втором – действительное время выполнения процесса в минутах, секундах и десятых долях секунды. В третьем столбце приведено «пользовательское» время, то есть время, занятое частями программы, не являющимися системными вызовами. Из-за дискретности используемого таймера одно из значений в таблице ошибочно записано как нулевое. В последнем, четвертом, столбце приведено время, затраченное ядром на обслуживание системных вызовов. Как видно из таблицы, третий и четвертый столбцы в сумме не дают действительное время выполнения. Это связано с тем, что в системе UNIX одновременно выполняется несколько процессов. Не все время тратится на выполнение ваших программ!

Полученные результаты достаточно убедительны – чтение и запись по одному байту дает очень низкую производительность, тогда как увеличение размера буфера значительно повышает производительность. Наибольшая производительность достигается, если BUFSIZE кратно размеру блока диска на диске, как видно из результатов, для значений BUFSIZE 512, 4096 и 8192 байта.

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

Функция fdFlush позволяет опустошить файловый буфер ядра UNIX для того, чтобы файл был действительно записан на диск.

Описание

uses linux;

Function fdFlush(fd:Longint):boolean;

2.1.10. Вызов fdseek и произвольный доступ

Системный вызов fdseek позволяет пользователю изменять положение указателя чтения-записи, то есть изменять номер байта, который будет первым считан или записан в следующей операции ввода/вывода. Таким образом, использование вызова fdseek позволяет получить произвольный доступ к файлу.

Описание

uses linux;

Function fdSeek(filedes, offset, SeekType:longint):longint;

Первый параметр, filedes, – это дескриптор открытого файла. Второй параметр, offset, обычно определяет новое положение указателя чтения-записи и задает число байтов, которое нужно добавить к начальному положению указателя. Третий целочисленный параметр, SeekType, определяет, что принимается в качестве начального положения, то есть откуда вычисляется смещение offset. Флаг SeekType может принимать одно из символьных значений (определенных в модуле linux), как показано ниже:

SEEK_SET

Смещение offset вычисляется от начала файла, обычно имеет значение = 0

SEEK_CUR

Смещение offset вычисляется от текущего положения в файле, обычное значение = 1

SEEK_END

Смещение offset вычисляется от конца файла, обычное значение = 2

Эти значения показаны в графическом виде на рис. 2.1, на котором представлен файл из 7 байт.

SEEK_SET

a

Текущее

b

положение

c

SEEK_CUR

указателя

d

файла

e

f

g

SEEK_END

Рис. 2.1. Символьные значения флага SeekType

Пример использования вызова fdseek:

var

newpos:longint;

.

.

.

newpos := fdseek(fd, -16, SEEK_END);

который задает положение указателя в 16 байтах от конца файла.

Во всех случаях возвращаемое значение (содержащееся в переменной newpos в примере) дает новое положение в файле. В случае ошибки оно будет содержать стандартный код ошибки -1.

Существует ряд моментов, которые следует отметить. Во-первых, обе переменные newpos и offset имеют тип longint, и должны вмещать смещение для любого файла в системе. Во-вторых, как показано в примере, смещение offset может быть отрицательным. Другими словами, возможно перемещение в обратную сторону от начального положения, заданного флагом SeekType. Ошибка возникнет только при попытке переместиться при этом на позицию, находящуюся до начала файла. В-третьих, можно задать позицию за концом файла. В этом случае, очевидно, не существует данных, которые можно было бы прочитать – невозможно предугадать будущие записи в этот участок (UNIX не имеет машины времени) – но последующий вызов fdwrite имеет смысл и приведет к увеличению размера файла. Пустое пространство между старым концом файла и начальным положением новых данных не обязательно выделяется физически, но для последующих вызовов fdread оно будет выглядеть как заполненное символами null ASCII.

В качестве простого примера мы можем создать фрагмент программы, который будет дописывать данные в конец существующего файла, открывая файл, перемещаясь на его конец при помощи вызова fdseek и начиная запись:

filedes := fdopen(filename, Open_RDWR);

fdseek(filedes, 0, SEEK_END);

fdwrite(filedes, outbuf, OBSIZE);

Здесь параметр направления поиска для вызова fdseek установлен равным SEEK_END для перемещения в конец файла. Так как перемещаться дальше нам не нужно, то смещение задано равным нулю.

Вызов fdseek также может использоваться для получения размера файла, так как он возвращает новое положение в файле.

var

filesize:longint;

filedes:integer;

.

.

.

filesize := fdseek(filedes, 0, SEEK_END);

Упражнение 2.8. Напишите функцию, которая использует вызов fdseek для получения размера открытого файла, не изменяя при этом значения указателя чтения-записи.

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal