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.