sql >> Database teknologi >  >> NoSQL >> Redis

Optimering af samtidige ImageMagick-anmodninger ved hjælp af redis/php-resque

Din kommando koger faktisk ned til dette:

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

Mine tanker er som følger:

Punkt 1:

Den første -composite på et tomt lærred virker meningsløst - formentlig 1.png er en 600x400 PNG med gennemsigtighed, så din første linje kan undgå sammensætningen og spare 16 % af behandlingstiden ved at ændre til:

convert -background none 1.png -fill ... -colorize 100% \
   \( 2.png ..
   \( 3.png ...

Punkt 2

Jeg lagde det svarende til din kommando i en loop og lavede 100 iterationer, og det tager 15 sekunder. Jeg ændrede derefter alle dine læsninger af PNG-filer til læsninger af MPC filer - eller Magick Pixel Cache-filer. Det reducerede behandlingstiden til knap 10 sekunder, det vil sige med 33 %. En Magic Pixel Cache er blot en præ-dekomprimeret, præ-dekodet fil, der kan læses direkte ind i hukommelsen uden nogen CPU-anstrengelse. Du kan på forhånd oprette dem, når dit katalog ændres, og gemme dem sammen med PNG-filerne. For at lave en gør du

convert image.png image.mpc

og du får ud af image.mpc og image.cache . Så ville du blot ændre din kode til at se sådan ud:

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

Punkt 3

Desværre har du ikke besvaret mine spørgsmål endnu, men hvis dit aktivkatalog ikke er for stort, kan du lægge det (eller MPC-ækvivalenterne ovenfor) på en RAM-disk ved systemstart.

Punkt 4

Du bør helt sikkert køre parallelt - det vil give den største gevinst af alle. Det er meget enkelt med GNU Parallel - eksempel her.

Hvis du bruger REDIS, er det faktisk nemmere end som så. Bare LPUSH dine MIME-kodede billeder til en REDIS-liste som denne:

#!/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);

og derefter køre flere arbejdere, der alle sidder der og laver BLPOPs af jobs, der skal udføres

#!/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);

Hvis jeg kører én generatorproces som ovenfor og får den til at generere 100.000 billeder på hver 200 kB og læse dem op med 4 arbejdsprocesser på min rimelige spec iMac, tager det 59 sekunder, eller omkring 1.700 billeder/s kan passere gennem REDIS.



  1. MongoDB $dateToParts

  2. Sådan gendannes en specifik samling i MongoDB ved hjælp af logisk sikkerhedskopiering

  3. MongoDB Whitespace-tegn

  4. Hent en værdi fra MongoDB efter dets nøglenavn