2011-12-04 50 views
1

我有一个图像上传servlet,它通过HTTP POST接收上传的图像,并且是大小从5 MB到75 MB不等的高分辨率图像。图像数据从请求输入流中读取并保存到本地磁盘上。我正在寻找一种有效的机制来从请求输入流中并行生成缩略图(或部分连续的,如果不是完全平行的)不同大小(4-5种不同大小,其中最大的是webimage - 1024x768),并将流保存到磁盘作为原始上传的文件。从单个图像流高效地生成多个缩略图

我现在能想到的是,直到 -

  1. 保存原始流作为图像文件保存到磁盘。
  2. 生成webimage(1024x768),这是该批量缩略图中最大的一个。
  3. 然后用它来生成后续较小的图像,因为它会更快。

有人能请建议一个更好的有效方法吗?最理想的方法是同步执行此操作,但如果非常有效,异步也很好。

在这方面的任何帮助将非常赞赏用Jav​​a。

回答

0

这是一个非常有趣的问题,因为它有很多优化点。

关于生成一个较小的图像然后生成缩略图的想法可能是一个很好的想法,但我要说的第一件事是,如果你有一个75MB的图像,那么它显然比1024x768大得多 - 最有可能的几倍在这种情况下,您希望确保使用SCALE_FAST缩放图像(Image)。你想要实现的是缩放比例缩小图像,通过丢弃像素而不是尝试做更好看的(并且更昂贵的)区域平均等任何事情。您甚至可以通过抓住图像的int []并对每个第N个元素进行采样,以便为新图像创建一个新的int [],并以某种因子缩小比例,从而使其更快。

在这一点上,你将有一个较小的图像,说2000年大约2000年。然后,你可以采取该图像和缩放它使用更好的寻找像SCALE_SMOOTH实际缩略图。

我会说,你应该而不是如果可能的话(无论如何处理)写入磁盘。如果你可以在内存中执行操作,它将会更快,并且在并行性的情况下是非常重要的。除非您的服务器正在运行SSD,然后同时运行两个磁盘繁重的操作(例如其中两个图像被同时重新缩放或者一个图像被重新缩放到两个不同的大小)将会强制磁盘出现颠簸(因为主轴一次只能读取一个流)。然后,你将受到你寻求时间的控制,你很快就会发现,连续化所有的操作将比一次完成多个操作要快得多。

我会说他们在内存中重新调整它们,然后将它们写入(同步)到ArrayList,然后让另一个线程顺序读取这些图像并存储它们。如果你不知道我在说什么,然后看看我的回答另一个问题在这里:

Producer Consumer solution in Java

这样你parallelise其中的有用(CPU运算)和你做的文件顺序写入(避免颠簸)。

话虽如此,你需要问自己,如果并行将会使你受益。你的服务器是否有多个CPU /内核?如果不是,那么这是毫无意义的,你应该不会打扰任何东西,因为它只会让你失去时间。

此外,如果您希望一次上传很多这些图像,那么您可能不需要平行处理每个图像,因为您将最终获得多个网络服务器线程,每个线程最多处理一个图像的时间,无论如何,这将为您在多个核心上提供良好的CPU利用率。例如,如果您期望在任何时候都会有4个图像不断上传,那么这将使用4个内核,而不需要进一步的并行处理。

最后一点需要注意的是,当您重新调整图像尺寸时,一旦拥有了中间图像,您可以将之前的图像设置为空以方便垃圾收集,这意味着当您生成缩略图时,内存,而不是原来的大尺寸。

0

让我看看,如果我得到这个权利,

你有一个大的图像,并希望在同一时间就可以执行不同的操作。一些操作涉及磁盘IO。

选项1 启动1个线程将原始hi res图像保存到磁盘。与其他操作相比,这会花费很长时间,因为磁盘写入速度很慢。 开始其他线程创建所需大小的缩略图。您需要调整原始图像的大小。我相信这可以通过克隆原始图像的字节来完成(在java中,我假设BufferedImage)。然后,您可以根据您希望的尺寸调整克隆大小。调整大小操作比写入磁盘更快。

如果每个缩略图有1个线程,则可以使用这些线程将其缩略图保存到磁盘。问题在于你会快速制作缩略图,并且所有这些线程几乎一次写入磁盘。这里的问题是它们可能被发送到不同的磁盘位置,而不是被分组到磁盘上的同一物理区域(局部性问题)。结果是,磁盘写入将比不并行地执行此操作慢,因为磁盘必须寻找新的位置并写入一些数据,然后CPU执行上下文切换并接受另一个将写入另一个部分的线程的磁盘(所以另一个寻求)等。所以这个想法很慢。

注意:使用具有线程池的ExecutorService,而不是单个线程。在我的例子中,我为每个缩略图使用了1个线程,因为它使得它更容易解释。

选项2, 你可以做的另一种方式是指定一个线程做写盘,和其他几个工作线程做调整。将所有thmubnails缓存到一个列表中,写入磁盘的线程将把它们一个接一个地写出来。

选项3, 最后,如果你有多个磁盘,你可以给每个线程的磁盘写入,那么所有写入将在平行(或多或少)。

如果您有RAID,写入速度会更快,但速度并不像上面刚刚提到的那么快,因为文件并非以并行方式串行写入。 RAID将同一文件的一部分写入并行化(一次写入不同的磁盘)。