簡體   English   中英

使用 redis/php-resque 優化並發 ImageMagick 請求

[英]Optimising concurrent ImageMagick Requests using redis/php-resque

我正在使用 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 進程方面有經驗的人,或者可以看到一些非常簡單的方法來優化我們的請求,我會非常感激。

謝謝 :)

您的命令實際上歸結為:

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透明,所以你的第一行可以通過改變來避免合成操作,節省處理時間16%:

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.mpcimage.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,它實際上比這更容易。 只需LPUSH您的 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);

然后運行多個工人,他們都坐在那里做 BLPOP 的工作

#!/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。

一次處理一個隊列? 您是否嘗試過並發作業,它會保持並行運行,因此如果是這種情況,您可以同時處理多個元素?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM