#php #gd
#php #gd
Вопрос:
Мне нужно сгенерировать и сохранить в базе данных множество небольших (1-10 КБ) изображений в формате PNG (> 10 миллионов). Единственное, что меня волнует, это пропускная способность изображений в секунду. На данный момент я знаю два способа сохранения объекта GD image в базе данных:
Используйте выходной буфер:
ob_start();
imagepng($image);
$imageData = ob_get_contents();
ob_end_clean();
Используйте временный файл (tmpfs / ramfs):
$tmpFilePath = '/dev/shm/file_000.png';
imagepng($image, $tmpFilePath);
$imageData = file_get_contents($thumbnail);
Обновить. Существует третий способ: использовать поток памяти PHP:
// PHP streams are NOT supported
$tmpFilePath = 'php://memory';
imagepng($image, $tmpFilePath);
$imageData = file_get_contents($tmpFilePath);
Мой вопрос в том, существуют ли какие-либо другие способы записи изображений в БД? Любые плюсы / минусы каждого метода.
Может быть, стоит написать пользовательский поток, который записывает данные в БД напрямую?
Примечание: Сохранение изображений в файловой системе не является вариантом.
Результаты тестирования:
Комментарии:
1. написание пользовательского метода, который передает потоки в базу данных, было бы действительно неплохо, но я не уверен, какие серверы баз данных поддерживают потоковую передачу больших двоичных объектов
Ответ №1:
Вы могли бы попробовать разрешить imagepng()
запись в поток памяти вместо файла.
$tmpFilePath = 'php://memory/file_000.png';
imagepng($image, $tmpFilePath);
$imageData = file_get_contents($tmpFilePath);
Хотя я не уверен, что imagepng()
функция может обрабатывать потоки ввода-вывода, если это так, это может быть хорошей альтернативой.
Ответ №2:
Я не думаю, что есть какой-либо другой способ: imagepng()
не имеет возможности возвращать поток данных (на мой взгляд, ошибка проектирования, но что вы собираетесь делать).
Какой из вышеупомянутых способов лучше для вас, вы должны протестировать; возможно, стоит написать оболочку stream, потому что это экономит этап записи файла.
Комментарии:
1. Я подготовлю тест чуть позже. Сейчас я сосредотачиваюсь на возможных вариантах.
Ответ №3:
Запись изображения во временный файл только увеличит объем дискового ввода-вывода, поэтому использование буфера памяти является хорошим выбором. Затем вы можете загрузить их в БД с помощью функции send_long_data подготовленного оператора. (Но вы, вероятно, уже знаете это.)
Комментарии:
1. Я не уверен, использую ли я send_long_data (это стоит другого вопроса). Что вы имеете в виду, говоря «буфер памяти»?
2. Я имел в виду
$imageData = ob_get_contents();
строку, когда вы загружаете изображение в память.
Ответ №4:
Оба варианта вряд ли повлияют на ваше общее время выполнения, поскольку в наши дни openreadclose’in кэшированного файла в Linux занимает около 20 микросекунд. Генерация и сжатие изображений потребуют много времени (сначала вы должны оптимизировать ту часть, которая занимает больше всего времени). Если вы действительно хотите сэкономить 1% от общего времени, используйте функции ob_().
В любом случае, если вы хотите сохранить их в базе данных, проверьте производительность вашей библиотеки подключения к базе данных с помощью больших двоичных объектов, некоторые из них довольно ужасны, другие быстры.
Комментарии:
1. В моем случае большие двоичные объекты небольшие, поэтому есть надежда достичь действительно хорошей производительности 🙂
2. Вы ошибаетесь насчет time-eater. 10k изображений генерируются за 16 секунд (на двух ядрах Xenon 5650). Генерация и запись всех изображений на жесткий диск занимает 187 секунд, хотя причиной может быть метод imagepng.
3. Сохранение 10000 файлов займет меньше секунды (если вы, конечно, не используете NTFS); однако PNG включает сжатие, которое требует времени. Можете ли вы предоставить несколько примеров изображений?
4. Как вы можете видеть из результатов, запись в память 10k в 3 раза быстрее. Общая экономия времени составляет более 1%.