我在一个网站上工作,使用ImageMagick来生成图像。网站每分钟都会收到数以百计的请求,使用ImageMagick这样做会导致网站崩溃。
所以我们实现了Redis和Php-resque来在一个独立的服务器上在后台生成ImageMagick,这样它就不会使我们的主服务器崩溃。问题是它仍然需要很长的时间来完成图像。用户可能希望为图像请求等待2-3分钟,因为服务器正忙于处理这些图像。
我不确定应该给你提供什么信息,但我更多的是寻求建议。我认为如果我们可以减少ImageMagick请求的初始处理时间,那么显然这将有助于加快我们可以处理的图像数量。
下面是我们使用的ImageMagick脚本示例:
convert -size 600x400 xc:none \( ".$path."assets/images/bases/base_image_69509021433289153_8_0.png -fill rgb\(255,15,127\) -colorize 100% \) -composite \( ".$path."assets/images/bases/eye_image_60444011438514404_8_0.png -fill rgb\(15,107,255\) -colorize 100% \) -composite \( ".$path."assets/images/markings/marking_clan_8_marking_10_1433289499.png -fill rgb\(255,79,79\) -colorize 100% \) -composite \( ".$path."assets/images/bases/shading_image_893252771433289153_8_0.png -fill rgb\(135,159,255\) -colorize 100% \) -compose Multiply -composite \( ".$path."assets/images/highlight_image_629750231433289153_8_0.png -fill rgb\(27,35,36\) -colorize 100% \) -compose Overlay -composite \( ".$path."assets/images/lineart_image_433715161433289153_8_0.png -fill rgb\(0,0,0\) -colorize 100% \) -compose Over -composite ".$path."assets/generated/queue/tempt_preview_27992_userid_0_".$filename."_file.png我的理论是,这需要相当长的时间的原因是由于对图像着色的过程。有没有办法优化这个过程呢?
任何有处理大量imagemagick进程的经验的人,或者能看到一些非常简单的方法来优化我们的请求的人,我都会非常高兴。
谢谢您:)
发布于 2015-08-28 17:43:32
您的命令实际上可以归结为:
convert -size 600x400 xc:none \
\( 1.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 2.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 3.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 4.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 5.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 6.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \
result.png我的想法如下:
要点1:
空白画布上的第一个-composite看起来毫无意义--假设1.png是一个600x400透明的PNG,因此您的第一行可以避免合成操作,并通过更改为:
convert -background none 1.png -fill ... -colorize 100% \
\( 2.png ..
\( 3.png ...点2
我把你的命令的等价物放入一个循环中,做了100次迭代,这需要15秒。然后,我将所有读取PNG文件的内容更改为读取MPC文件-或Magick Pixel Cache文件。这将处理时间减少到略低于10秒,即33%。Magic Pixel Cache只是一个预解压、预解码的文件,可以直接读取到内存中,而不需要任何CPU工作。您可以在目录更改时预先创建它们,并将它们与PNG文件一起存储。做一个你想做的事
convert image.png image.mpc你就能把image.mpc和image.cache弄出来。然后,您只需将代码更改为如下所示:
convert -size 600x400 xc:none \
\( 1.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 2.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 3.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 4.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 5.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
\( 6.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \
result.png点3
不幸的是,您还没有回答我的问题,但是如果您的资产目录不是太大,您可以在系统启动时将其(或上面的MPC等价物)放到RAM磁盘上。
点4
您绝对应该并行运行-这将产生最大的收益。使用GNU Parallel - example here非常简单。
如果你使用的是REDIS,它实际上比这更容易。只需将您的MIME编码图像LPUSH到一个REDIS列表中,如下所示:
#!/usr/bin/perl
################################################################################
# generator.pl <number of images> <image size in bytes>
# Mark Setchell
# Base64 encodes and sends "images" of specified size to REDIS
################################################################################
use strict;
use warnings FATAL => 'all';
use Redis;
use MIME::Base64;
use Time::HiRes qw(time);
my $Debug=0; # set to 1 for debug messages
my $nargs = $#ARGV + 1;
if ($nargs != 2) {
print "Usage: generator.pl <number of images> <image size in bytes>\n";
exit 1;
}
my $nimages=$ARGV[0];
my $imsize=$ARGV[1];
# Our "image"
my $image="x"x$imsize;
printf "DEBUG($$): images: $nimages, size: $imsize\n" if $Debug;
# Connection to REDIS
my $redis = Redis->new;
my $start=time;
for(my $i=0;$i<$nimages;$i++){
my $encoded=encode_base64($image,'');
$redis->rpush('images'=>$encoded);
print "DEBUG($$): Sending image $i\n" if $Debug;
}
my $elapsed=time-$start;
printf "DEBUG($$): Sent $nimages images of $imsize bytes in %.3f seconds, %d images/s\n",$elapsed,int($nimages/$elapsed);然后运行多个工作者,这些工作者都坐在那里做大量要做的工作
#!/usr/bin/perl
################################################################################
# worker.pl
# Mark Setchell
# Reads "images" from REDIS and uudecodes them as fast as possible
################################################################################
use strict;
use warnings FATAL => 'all';
use Redis;
use MIME::Base64;
use Time::HiRes qw(time);
my $Debug=0; # set to 1 for debug messages
my $timeout=1; # number of seconds to wait for an image
my $i=0;
# Connection to REDIS
my $redis = Redis->new;
my $start=time;
while(1){
#my $encoded=encode_base64($image,'');
my (undef,$encoded)=$redis->blpop('images',$timeout);
last if !defined $encoded;
my $image=decode_base64($encoded);
my $l=length($image);
$i++;
print "DEBUG($$): Received image:$i, $l bytes\n" if $Debug;
}
my $elapsed=time-$start-$timeout; # since we waited that long for the last one
printf "DEBUG($$): Received $i images in %.3f seconds, %d images/s\n",$elapsed,int($i/$elapsed);如果我像上面那样运行一个生成器进程,让它生成100,000个200kB的图像,并在我合理的规范iMac上用4个工作进程读取它们,它需要59秒,或者说大约1,700个图像/秒可以通过REDIS。
发布于 2015-08-28 02:30:47
队列是一次处理一个队列吗?你有没有尝试过让并发作业保持并行运行,这样你就可以同时处理多个元素了?
https://stackoverflow.com/questions/32256831
复制相似问题