PHP-скрипты: оптимизация копирования файлов

Октябрь 31, 2007

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

На текущий момент я вижу много вариантов развития данного действия.
1. Использование стандартных функций:
— листинг директории и использования функции copy для каждого из файлов
— листинг директории и использования более низкоуровневых функций, реализующих копирование в следующих комбинациях
fopen ('File', 'r+b') — fput
fopen ('File', 'r+b') — fwrite
2. Использование бинарника cp из стандартной поставки Linux-системы
— для каждого из файлов
— сразу для всех файлов директории

Для теста я выбираю папку с различными типами файлов: текстовые, графические, бинарные, архивы, mp3 (всего — на 24.8mb)
На вскидку, предполагаю следующий вариант развития событий
Быстрее всех справится с задачей бинарник с копированием файлов по маске «*» из папки в папку.
После будет бинарник с пофайловым копированием.
Далее — стандартная функция copy
Далее — примерно одинаково fput/fwrite с 4Kb буфером.

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

<?php

$d = @opendir („.“);
while (($e=readdir ($d)) !== false)
{
if ($e=='.' || $e=='...') continue;
if (!@is_dir ($e))
{ /* — COPY PROCESS — */ };
}

?>

Для тестировния быстродействия мы используем скрипты из предыдущей статьи (стандартные функции).

Чуток поработав, мы получаем следующий код для стандартной функции copy

<?php

$from = '/home/jeurey/testdir';
$to = $from.'/dest';

echo '

Тестировние стандартной функции copy на предмет целесообразности использования в копировании файлов
';
$av_time_arr = array ();
$tmp_arr = array ();

$tmp_arr = explode (' ',microtime ());
$ex_start_mtime = $tmp_arr[0]+$tmp_arr[1];

$d = @opendir („/home/jeurey/testdir“);
while (($e=readdir ($d)) !== false)
{
if ($e=='.' || $e=='...') continue;
if (!@is_dir ($e))
{ echo 'COPY PROCESS '.$e;
if (copy ($from.'/'.$e, $to.'/'.$e)) echo ' done';
echo '
'."\n";
}

}
$tmp_arr = explode (' ', microtime ());
$ex_stop_mtime= $tmp_arr[0]+$tmp_arr[1];
$ex_mtime = ($ex_stop_mtime-$ex_start_mtime);

echo 'Время старта скрипта: '.$ex_start_mtime.' cек
';
echo 'Время остановки скрипта: '.$ex_stop_mtime.' сек
';
echo 'Время работы скрипта: '.$ex_mtime.' секунд
';

?>

Результат работы:

COPY PROCESS cron.log2.txt done
COPY PROCESS d done
COPY PROCESS pdt-all-in-one-incubation-S20070910_RC1-linux-gtk.tar.gz done
COPY PROCESS Firefox_wallpaper.png done
COPY PROCESS dest
COPY PROCESS nautilus-debug-log.txt done
COPY PROCESS pdt-all-in-one-1.0-R20070917-win32.zip done
COPY PROCESS templates.tar.gz done
Время старта скрипта: 1193827626.44 cек
Время остановки скрипта: 1193827658.82 сек
Время работы скрипта: 32.3768770695 секунд

Переходим к тестированию метода fread/fputs


<?php

$from = '/home/jeurey/testdir';
$to = $from.'/dest';

echo '<h2>Тестировние стандартной функций fopen_fput на предмет целесообразности использования в копировании файлов</h2>';
$av_time_arr = array ();
$tmp_arr = array ();

$tmp_arr = explode (' ',microtime ());
$ex_start_mtime = $tmp_arr[0]+$tmp_arr[1];

$d = @opendir ($from);
while (($e=readdir ($d)) !== false)
{
if ($e=='.' || $e=='...') continue;
if ($e != 'dest')
{ echo 'COPY PROCESS '.$e;

$fR = fopen ($from.'/'.$e,'r+b');
$fW = fopen ($to.'/'.$e,'w+b');
while (!feof ($fR))
{ fputs ($fW,fread ($fR,4096)); //Буфер в 4кб
}
fclose ($fR);
fclose ($fW);
if (filesize ($to.'/'.$e)>0) echo ' done';
echo '<br />'."\n";
}

}
$tmp_arr = explode (' ', microtime ());
$ex_stop_mtime= $tmp_arr[0]+$tmp_arr[1];
$ex_mtime = ($ex_stop_mtime-$ex_start_mtime);

echo 'Время старта скрипта: '.$ex_start_mtime.' cек<br />';
echo 'Время остановки скрипта: '.$ex_stop_mtime.' сек<br />';
echo 'Время работы скрипта: '.$ex_mtime.' секунд<br />';

?>

Результаты работы

не утешают: время выполнения скрипта больше 100 секунд. Сколько — не важно, главное, что копирование данным методом нам не подходит.

И, наконец, последний, заключительный тест. Используем бинарник /bin/cp для копирования файлов. На него я делаю ставку :)


<?php
echo '<h2>Тестировние стандартных функции на предмет скорости копирования</h2>';

$from = '/home/jeurey/testdir';
$to = $from.'/dest';

$av_time_arr = array ();
$tmp_arr = array ();

$tmp_arr = explode (' ',microtime ());
$ex_start_mtime = $tmp_arr[0]+$tmp_arr[1];

exec ('sudo cp '.$from.'/* '.$to);

$tmp_arr = explode (' ', microtime ());
$ex_stop_mtime= $tmp_arr[0]+$tmp_arr[1];
$ex_mtime = ($ex_stop_mtime-$ex_start_mtime);

echo 'Время старта скрипта: '.$ex_start_mtime.' cек<br />';
echo 'Время остановки скрипта: '.$ex_stop_mtime.' сек<br />';
echo 'Время работы скрипта: '.$ex_mtime.' секунд<br />';
?>

Ну, и результат, конечно :)

Время старта скрипта: 1193829335.65 cек
Время остановки скрипта: 1193829337.82 сек
Время работы скрипта: 2.16994690895 секунд

Думаю, целесообразность использования бинаря Вам уже ясна.
Good Luck, как говорится :)

Комметирование закрыто.