如何使图像生成在Java中可扩展?

时间:2010-10-13 09:51:24

标签: java performance graphics scalability

我正在尝试提高在Linux上运行的Web应用程序中验证码图像渲染的性能。看看目前使用的是什么,我发现瓶颈在于使用Java2D,特别是Graphics2D类。

问题不在于执行速度,而在于可扩展性。基本上它不会扩展。在1个线程或2个线程中绘制验证码图像在执行时间方面没有任何改进。

作为示例,您可以查看以下用于为验证码图像创建背景的类。在调用Graphics2D :: setColor()和Graphics2D :: drawLine()时会出现问题:

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

经过一些谷歌搜索后,我发现主题说Java2d在多线程方面不是特别好(抱歉,不允许提供多个链接:)但是,如果google为'java2d multithreading',你可以轻松找到该主题,这将是第一个结果)

我相信必须有一些库提供绘图功能而不使用Java2d,但未能找到它:(或者Java2d,可能,可以切换到某种模式,这不会阻止访问图形对象(顺便说一句) ,无头模式没有帮助。)

我将不胜感激任何建议。事先,谢谢你的回答。

2 个答案:

答案 0 :(得分:1)

没有一种快速的方式来共享可预测的Graphics2D,因为除非你有办法在每个像素上进行同步和重新排序,否则这将是一个巨大的竞争条件。

无论如何,Graphics2DBufferedImage支持,这可能会减慢您的速度。这是一个非加速的表面,因此绘图总是非常慢。如果您的渲染服务器具有适合它的图形硬件(对于像这样的应用程序,它确实应该这样),您可以使用VolatileImage,它比全局BufferedImage大约一个数量级或两个快{2}。我的经验。

否则,你必须将你的背景世代切成一个网格,AffineTransform它们全部排成一行,通过播种将所有网格元素的“随机性”共同化,将它们拼接回来后来并希望copyArea(...)方法足够快,可以为您提供改进。我几乎会说这是一个kludge,硬件加速是要走的路。

您还应该考虑将大量离线预渲染离线,并根据需要提供它们。这样,性能或多或少都不会成为问题,除非您在服务器空闲时间内无法满足需求(在这种情况下,您需要新的硬件,只需要制作硬件加速渲染框)。

答案 1 :(得分:0)

基于简要查看代码的一些优化建议:

  • 您正在为每个验证码创建一个新的BufferedImage。我认为你最好在ThreadLocal变量中为每个线程保留一个BufferedImage和Graphics2D,并在创建一个新的一个验证码时绘制它们
  • 你正在为每个像素做一个大循环,每个像素需要大量的计算。您希望绝对最小化在此循环中间完成的计算,例如在循环外做“colorRightDown.getRed()/ 255.0f”等的常量计算
  • 考虑将所有浮点计算转换为等效的定点整数数学。这通常会稍微快一些,只要你可以使所有东西都适合整数。
  • 使用带有整数颜色值的BufferedImage.setRGB()而不是带有新颜色的Graphics2D.setColor - 它会更快更多并为您节省大量GC压力
  • 看看你是否可以减少每个像素的随机数调用次数,我每个像素数为7个....你能不能轻易逃脱?您可能更好地创建随机整数并测试位的子集。
  • 在内部(i)循环中使用width而不是getImageWidth(),否则您将为每个像素不必要地调用getImageWidth。对于(j)循环也是如此,尽管它更不重要。

我的猜测是,上面的组合将获得远远超过抛出额外处理器的问题.....: - )