Как сделать генерацию изображений масштабируемой на Java? - PullRequest
2 голосов
/ 13 октября 2010

Я пытаюсь улучшить производительность рендеринга капч изображения в веб-приложении на Linux. Глядя на то, что в настоящее время используется, я обнаружил, что узким местом является использование Java2D и, в частности, класса Graphics2D.

Проблема не столько в скорости выполнения, сколько в масштабируемости. В основном это не масштабируется. Рисование изображений капчи в 1 или 2 потоках не приводит к улучшению времени выполнения.

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

http://www.docjar.com/html/api/com/octo/captcha/component/image/backgroundgenerator/FunkyBackgroundGenerator.java.html

После некоторого поиска в Google, я обнаружил тему, в которой говорится, что Java2d не особенно хорошо подходит для многопоточности (извините, не разрешено давать более одной ссылки :), но вы можете легко найти эту тему, если Google использует 'многопоточность java2d' , это будет первый результат)

Я считаю, что должна быть какая-то библиотека, которая обеспечивает возможности рисования без использования Java2d, но не смогла найти его :( Или Java2d, возможно, можно переключить в какой-то режим, который не блокирует доступ к графическому объекту (кстати безголовый режим не помогает).

Буду признателен за любые предложения. Заранее спасибо за ответы.

Ответы [ 2 ]

1 голос
/ 13 октября 2010

Не будет быстрого способа поделиться Graphics2D, который работает предсказуемо, потому что, если бы у вас не было способа синхронизировать и переупорядочить каждый пиксель, это было бы массовым соревнованием.

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

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

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

0 голосов
/ 14 октября 2010

Некоторые идеи по оптимизации, основанные на кратком обзоре вашего кода:

  • Вы создаете новый BufferedImage для каждой капчи.Я думаю, что вам лучше оставить по одному BufferedImage и Graphics2D на поток в переменных ThreadLocal и рисовать поверх предыдущей капчи всякий раз, когда вы создаете новую
  • Вы делаете большой цикл для каждого пикселя с большим количеством вычислений для каждогопиксели.Вы хотите абсолютно минимизировать вычисления, выполненные в середине этого цикла, например, делать постоянные вычисления "colorRightDown.getRed () / 255.0f" и т. Д. Вне цикла
  • Рассмотрите возможность преобразования всех вычислений с плавающей запятой вэквивалентные целые числа с фиксированной запятой.Обычно это немного быстрее, при условии, что все можно уместить в целых.
  • Используйте BufferedImage.setRGB () с целочисленными значениями цвета, а не Graphics2D.setColor с новым цветом - это будет намного быстрее и сэкономит вам большое давление ГХ
  • Посмотрите, можете ли вы уменьшить количество вызовов случайных чисел на пиксель, я считаю 7 на пиксель.Возможно, вам лучше создать случайное целое число и проверить подмножества битов.
  • Используйте ширину, а не getImageWidth () в вашем внутреннем (i) цикле, иначе вы без необходимости вызываете getImageWidth для каждого пикселя.То же самое для цикла (j), хотя это имеет гораздо меньшее значение.

Я предполагаю, что объединенное выше принесет вам гораздо больше, чем использование дополнительных процессоров при решении проблемы ..... :-)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...