Как оптимизировать использование процессора ImageMagick на сервере - PullRequest
0 голосов
/ 27 декабря 2018

Я пытаюсь наложить изображение поверх другого изображения с помощью ImageMagick.Я установил машину AWS beanstalk с 16-ядерным процессором с 32-Гбайтным ОЗУ (c5 4x) и запускаю код в среде Go.Всякий раз, когда запрос GET попадает на сервер, выполняется следующая команда оболочки. Вот команда, которую я запускаю

cmd := "convert "+ img1 + " -page +"+fmt.Sprintf("%.1f", offsetX)+"+"+fmt.Sprintf("%.1f", offsetY) + " " + img2 + " -background none -flatten "+outputFilePath
cmdout,err := exec.Command("sh","-c",cmd).CombinedOutput()
//convert img1.png -page +10+10 img2.png -background none -flatten  output.png

img1 имеет размер около 500x500, а im2 - около 200x200

Iвыполнил нагрузочный тест и обнаружил, что текущая настройка может обрабатывать только 15 запросов в секунду с использованием процессора 51%.При 25req / sec загрузка процессора становится 95%.Я твердо верю, что я что-то не так делаю.Я использую Imagemagick v6.7.8.Поможет ли обновление до последней версии или компиляция ImageMagick из исходного кода (вместо установки yum)?

Что я должен делать, чтобы соответствовать 100req / sec и убедиться, что все vCPU оптимально используются

1 Ответ

0 голосов
/ 28 декабря 2018

Я пробовал на своем ноутбуке i5 2015 года (два ядра, четыре потока).Я сделал несколько тестовых данных, таких как:

$ mkdir sample
$ cd sample
$ vipsheader ../fg.png ../bg.png 
../fg.png: 200x200 uchar, 4 bands, srgb, pngload
../bg.png: 500x500 uchar, 4 bands, srgb, pngload
$ for i in {0..1000}; do cp ../fg.png fg$i.png; done
$ for i in {0..1000}; do cp ../bg.png bg$i.png; done

Итак, 1000 PNG изображений 500x500 и 200x200.

Сначала базовый вариант (IM 6.9.10):

$ time for i in {0..1000}; do convert bg$i.png -page +10+10 fg$i.png -background none -flatten out$i.png; done
real    0m49.461s
user    1m4.875s
sys 0m6.690s

49 с - это примерно 20 операций в секунду.

Далее я попробовал с GNU параллельно.Это простой способ запустить достаточное количество из них параллельно, чтобы поддерживать загрузку всех ядер:

$ time parallel convert bg{}.png -page +10+10 fg{}.png -background none -flatten  out{}.png ::: {0..1000}
real    0m32.278s
user    1m46.428s
sys 0m11.897s

32s - 31 ops / секунда.Это на двухъядерном ноутбуке - вы бы увидели лучшее ускорение с большим настольным компьютером.

Наконец, я написал крошечную программу pyvips , чтобы выполнить вашу задачу.pyvips - это привязка Python для libvips , но есть и привязки Go.

import pyvips

for i in range(0, 1000):
    bg_name = "bg" + str(i) + ".png"
    fg_name = "fg" + str(i) + ".png"
    out_name = "out" + str(i) + ".png"

    bg = pyvips.Image.new_from_file(bg_name, access="sequential")
    fg = pyvips.Image.new_from_file(fg_name, access="sequential")

    result = bg.composite2(fg, "over", x=10, y=10)

    result.write_to_file(out_name)

Я вижу:

$ time ~/try/try289.py 
real    0m25.887s
user    0m36.625s
sys 0m1.442s

26s - это около 40 операций в секунду.Вы могли бы получить это немного быстрее, если бы запускали несколько параллельно.

Одно из ограничений, которое вы используете, - это формат PNG - библиотека однопоточная и довольно медленная.Если вы хотите попробовать TIFF, вы можете получить немного больше скорости.

TIFF со сжатием с дефляцией функционально аналогичен PNG.Если я попытаюсь:

$ vips copy fg.png fg.tif[compression=deflate]
$ vips copy bg.png bg.tif[compression=deflate]
$ ls -l bg.*
-rw-r--r-- 1 john john 19391 Dec 27 20:48 bg.png
-rw-r--r-- 1 john john 16208 Jan  2 18:36 bg.tif

Так что на самом деле это немного меньше, в этом случае.Если я изменю программу pyvips на:

bg_name = "bg" + str(i) + ".tif"
fg_name = "fg" + str(i) + ".tif"
out_name = "out" + str(i) + ".tif[compression=deflate]"

И запустю ее, я увижу:

$ time ~/try/try289.py 
real    0m17.618s
user    0m23.234s
sys 0m1.823s

Около 55 операций в секунду.

...