J'ai le code suivant qui écrit les sommes md5 dans un fichier journal
for file in files_output:
p=subprocess.Popen(['md5sum',file],stdout=logfile)
p.wait()
Seront-ils écrits en parallèle? Par exemple, si md5sum prend beaucoup de temps pour l'un des fichiers, un autre sera-t-il démarré avant d'attendre la fin d'un précédent?
Si la réponse à ce qui précède est oui, puis-je supposer que l'ordre des sommes md5 écrites dans le fichier journal peut différer en fonction du temps que prend md5sum pour chaque fichier? (certains fichiers peuvent être énormes, certains petits)
Tous les sous-processus sont exécutés en parallèle. (Pour éviter cela, il faut attendre explicitement leur achèvement.) Ils peuvent même écrire dans le fichier journal en même temps, brouillant ainsi la sortie. Pour éviter cela, vous devez laisser chaque processus écrire dans un fichier journal différent et collecter toutes les sorties lorsque tous les processus sont terminés.
q = Queue.Queue()
result = {} # used to store the results
for fileName in fileNames:
q.put(fileName)
def worker():
while True:
fileName = q.get()
if fileName is None: # EOF?
return
subprocess_stuff_using(fileName)
wait_for_finishing_subprocess()
checksum = collect_md5_result_for(fileName)
result[fileName] = checksum # store it
threads = [ threading.Thread(target=worker) for _i in range(20) ]
for thread in threads:
thread.start()
q.put(None) # one EOF marker for each thread
Après cela, les résultats doivent être stockés dans result
.
De plus, votre façon de créer p.wait()
après la boucle for
attendra juste que le dernier des processus md5sum se termine et que le reste d'entre eux soit toujours en cours d'exécution.
Mais vous pouvez modifier légèrement ce code pour bénéficier des avantages du traitement parallèle et de la prévisibilité de la sortie synchronisée si vous collectez la sortie md5sum dans des fichiers temporaires et la recueillez dans un fichier une fois tous les processus terminés.
import subprocess
import os
processes = []
for file in files_output:
f = os.tmpfile()
p = subprocess.Popen(['md5sum',file],stdout=f)
processes.append((p, f))
for p, f in processes:
p.wait()
f.seek(0)
logfile.write(f.read())
f.close()
Un moyen simple de collecter la sortie des sous-processus parallèles md5sum consiste à utiliser un pool de threads et à écrire dans le fichier à partir du processus principal:
from multiprocessing.dummy import Pool # use threads
from subprocess import check_output
def md5sum(filename):
try:
return check_output(["md5sum", filename]), None
except Exception as e:
return None, e
if __name__ == "__main__":
p = Pool(number_of_processes) # specify number of concurrent processes
with open("md5sums.txt", "wb") as logfile:
for output, error in p.imap(md5sum, filenames): # provide filenames
if error is None:
logfile.write(output)
md5sum
est petite, vous pouvez donc la stocker en mémoireimap
conserve l'ordrenumber_of_processes
Peut être différent du nombre de fichiers ou de cœurs de processeur (des valeurs plus élevées ne signifient pas plus rapidement: cela dépend des performances relatives de IO (disques) et CPU)Vous pouvez essayer de passer plusieurs fichiers à la fois aux sous-processus md5sum.
Vous n'avez pas besoin de sous-processus externe dans ce cas; vous pouvez calculer md5 en Python :
import hashlib
from functools import partial
def md5sum(filename, chunksize=2**15, bufsize=-1):
m = hashlib.md5()
with open(filename, 'rb', bufsize) as f:
for chunk in iter(partial(f.read, chunksize), b''):
m.update(chunk)
return m.hexdigest()
Pour utiliser plusieurs processus au lieu de threads (pour permettre à la pure Python md5sum()
de fonctionner en parallèle en utilisant plusieurs CPU), il suffit de supprimer .dummy
De l'importation dans le au-dessus du code.