Redis
 sql >> база данни >  >> NoSQL >> Redis

Оптимизиране на едновременни заявки на ImageMagick с помощта на redis/php-resque

Вашата команда всъщност се свежда до това:

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 е PNG 600x400 с прозрачност, така че първият ви ред може да избегне операцията за композиране и да спести 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 е просто предварително декомпресиран, предварително декодиран файл, който може да бъде прочетен директно в паметта без никакви усилия на процесора. Можете да ги създадете предварително, когато каталогът ви се промени, и да ги съхранявате заедно с 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 е много просто - пример тук.

Ако използвате REDIS, всъщност е по-лесно от това. Просто LPUSH вашите MIME-кодирани изображения в списък 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 изображения от по 200 kB всяко и да ги прочета с 4 работни процеса на моята разумна спецификация iMac, това отнема 59 секунди или около 1700 изображения/сек могат да преминат през REDIS.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. използване на Async в транзакция в приложението Spring

  2. Redis SYNC и EXEC

  3. Мога ли да задам глобален TTL в redis?

  4. Как да разбера типа данни на стойността на даден ключ?

  5. Какво трябва да използвам? Socket.io стаи или Redis pub-sub?