Votre commande se résume en fait à ceci :
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
Mes pensées sont les suivantes :
Point 1 :
Le premier -composite
sur une toile vierge semble inutile - probablement 1.png
est un PNG 600x400 avec transparence, donc votre première ligne peut éviter l'opération de composition et gagner 16% du temps de traitement en changeant en :
convert -background none 1.png -fill ... -colorize 100% \
\( 2.png ..
\( 3.png ...
Point 2
J'ai mis l'équivalent de votre commande dans une boucle et j'ai fait 100 itérations et cela prend 15 secondes. J'ai ensuite changé toutes vos lectures de fichiers PNG en lectures de MPC
fichiers - ou fichiers Magick Pixel Cache. Cela a réduit le temps de traitement à un peu moins de 10 secondes, soit 33 %. Un Magic Pixel Cache est juste un fichier pré-décompressé et pré-décodé qui peut être lu directement dans la mémoire sans aucun effort CPU. Vous pouvez les créer à l'avance chaque fois que votre catalogue change et les stocker avec les fichiers PNG. Pour en faire un vous faites
convert image.png image.mpc
et vous obtiendrez image.mpc
et image.cache
. Ensuite, vous modifieriez simplement votre code pour qu'il ressemble à ceci :
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
Point 3
Malheureusement, vous n'avez pas encore répondu à mes questions, mais si votre catalogue d'actifs n'est pas trop volumineux, vous pouvez le mettre (ou les équivalents MPC ci-dessus) sur un disque RAM au démarrage du système.
Point 4
Vous devriez certainement courir en parallèle - cela vous rapportera les gains les plus importants de tous. C'est très simple avec GNU Parallel - exemple ici.
Si vous utilisez REDIS, c'est en fait plus simple que cela. Juste LPUSH
vos images encodées MIME dans une liste REDIS comme celle-ci :
#!/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);
puis exécutez plusieurs travailleurs qui sont tous assis là à faire des BLPOP de tâches à faire
#!/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);
Si j'exécute un processus de générateur comme ci-dessus et que je le fais générer 100 000 images de 200 Ko chacune, et que je les lis avec 4 processus de travail sur mon iMac aux spécifications raisonnables, cela prend 59 secondes, ou environ 1 700 images/s peuvent passer par REDIS.