有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

性能如何使图像生成在Java上可伸缩?

我正试图在Linux上运行的web应用程序中提高captcha图像呈现的性能。查看当前使用的内容,我发现瓶颈在于Java2D,特别是Graphics2D类的使用

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

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

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

通过谷歌搜索,我找到了一个主题,上面说Java2d不太适合多线程(对不起,不允许提供多个链接:),但是,如果谷歌搜索“Java2d多线程”,你很容易找到这个主题,这将是第一个结果)

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

如有任何建议,我将不胜感激。在此之前,谢谢你的回答


共 (2) 个答案

  1. # 1 楼答案

    基于对代码的简要了解,提出了一些优化建议:

    • 您正在为每个验证码创建一个新的BuffereImage。我认为最好是在ThreadLocal变量中为每个线程保留一个BuffereImage和Graphics2D,并在创建新的验证码时覆盖上一个验证码
    • 你在每个像素上做一个大循环,每个像素都有大量的计算。你想要绝对地最小化在这个循环的中间所做的计算,例如循环[考虑将所有浮点计算转换为等效的定点整数。这通常会稍微快一点,前提是你可以让所有东西都适合ints
    • 使用BuffereImage。setRGB()具有整数颜色值,而不是图形2D。用一种新颜色设置颜色-它将快得多并为您节省大量GC压力
    • 看看你能不能减少每像素的随机呼叫次数,我每像素数7次。。。。你能做得比这少吗?你最好创建一个随机整数并测试比特的子集
    • 在内部(i)循环中使用width而不是getImageWidth(),否则对每个像素调用getImageWidth是不必要的。(j)循环也是如此,尽管它的重要性要小得多

    我的猜测是,上述组合将为您带来的好处远远超过在这个问题上投入额外的处理器……:-)

  2. # 2 楼答案

    不可能有一种快速的方式来分享一个Graphics2D可以预期的效果,因为除非你有办法对每个像素进行同步和重新排序,否则这将是一个巨大的竞争条件

    不管怎么说,你的Graphics2D是由一个BufferedImage支持的,所以这可能是让你慢下来的原因。这是一个不加速的表面,所以画图总是很慢。如果你的渲染服务器有图形硬件(对于这样的应用程序来说应该是这样的),你可以使用一个^{},在我的经验中,它比一个BufferedImage要快一到两个数量级

    否则,你将不得不将背景生成分割成一个网格,AffineTransform让它们排成一行,通过播种使“随机性”在所有网格元素中变得普遍,然后在课后将它们重新缝合在一起,并希望copyArea(...)方法足够快,可以为你带来改进。我几乎可以说,这是一个混乱的局面,硬件加速才是出路

    你也应该考虑预先准备大量离线,并根据需要提供服务。这样的话,性能基本上是没有问题的,除非你在服务器空闲时间内无法满足需求(在这种情况下,你需要新的硬件,只需要制作一个硬件加速渲染盒)