sql >> Database >  >> NoSQL >> Redis

Gelijktijdige ImageMagick-verzoeken optimaliseren met redis/php-resque

Je commando komt hier eigenlijk op neer:

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

Mijn gedachten zijn als volgt:

Punt 1:

De eerste -composite op een leeg canvas lijkt zinloos - vermoedelijk 1.png is een 600x400 PNG met transparantie, dus uw eerste regel kan de compositing-bewerking vermijden en 16% van de verwerkingstijd besparen door te wijzigen naar:

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

Punt 2

Ik heb het equivalent van je commando in een lus geplaatst en 100 iteraties gedaan en het duurt 15 seconden. Ik heb toen al je reads van PNG-bestanden veranderd in reads van MPC bestanden - of Magick Pixel Cache-bestanden. Dat verminderde de verwerkingstijd tot iets minder dan 10 seconden, ofwel met 33%. Een Magic Pixel Cache is slechts een voorgedecomprimeerd, voorgedecodeerd bestand dat direct in het geheugen kan worden ingelezen zonder enige CPU-inspanning. U kunt ze vooraf maken wanneer uw catalogus verandert en ze naast de PNG-bestanden opslaan. Om er een te maken die je doet

convert image.png image.mpc

en je komt uit image.mpc en image.cache . Dan zou je gewoon je code veranderen om er als volgt uit te zien:

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

Punt 3

Helaas heb je mijn vragen nog niet beantwoord, maar als je activacatalogus niet te groot is, zou je die (of de MPC-equivalenten hierboven) op een RAM-schijf kunnen zetten bij het opstarten van het systeem.

Punt 4

Je moet zeker parallel lopen - dat levert de grootste winst op. Het is heel eenvoudig met GNU Parallel - voorbeeld hier.

Als u REDIS gebruikt, is het eigenlijk eenvoudiger dan dat. Gewoon LPUSH uw MIME-gecodeerde afbeeldingen in een REDIS-lijst zoals deze:

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

en voer vervolgens meerdere werknemers uit die daar allemaal BLPOP's van banen doen om te doen

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

Als ik één generatorproces uitvoer zoals hierboven en ik laat het 100.000 afbeeldingen van elk 200 kB genereren, en lees ze uit met 4 werkprocessen op mijn redelijk gespecificeerde iMac, dan duurt het 59 seconden, of ongeveer 1.700 afbeeldingen/s kunnen door REDIS gaan.



  1. MongoDB $asinh

  2. Hoe het ISO-datumformaat terug te geven in PHP voor MongoDB?

  3. Promoot subvelden naar het hoogste niveau in projectie zonder alle sleutels op te sommen

  4. Zoek uit of een zoekopdracht een index in MongoDB gebruikt