Muchos hilos para escribir el archivo de registro al mismo tiempo en Python

Estoy escribiendo un script para recuperar la información de WMI de muchas computadoras al mismo tiempo, luego escribo esta información en un archivo de texto:

f = open("results.txt", 'w+') ## to clean the results file before the start def filesize(asset): f = open("results.txt", 'a+') c = wmi.WMI(asset) wql = 'SELECT FileSize,Name FROM CIM_DataFile where (Drive="D:" OR Drive="E:") and Caption like "%file%"' for item in c.query(wql): print >> f, item.Name.split("\\")[2].strip().upper(), str(item.FileSize) class myThread (threading.Thread): def __init__(self,name): threading.Thread.__init__(self) self.name = name def run(self): pythoncom.CoInitialize () print "Starting " + self.name filesize(self.name) print "Exiting " + self.name thread1 = myThread('10.24.2.31') thread2 = myThread('10.24.2.32') thread3 = myThread('10.24.2.33') thread4 = myThread('10.24.2.34') thread1.start() thread2.start() thread3.start() thread4.start() 

El problema es que todos los hilos se escriben al mismo tiempo.

Simplemente puede crear su propio mecanismo de locking para asegurarse de que solo un hilo esté escribiendo en un archivo.

 import threading lock = threading.Lock() def write_to_file(f, text, file_size): lock.acquire() # thread blocks at this line until it can obtain lock # in this section, only one thread can be present at a time. print >> f, text, file_size lock.release() def filesize(asset): f = open("results.txt", 'a+') c = wmi.WMI(asset) wql = 'SELECT FileSize,Name FROM CIM_DataFile where (Drive="D:" OR Drive="E:") and Caption like "%file%"' for item in c.query(wql): write_to_file(f, item.Name.split("\\")[2].strip().upper(), str(item.FileSize)) 

Es posible que desee considerar colocar el candado alrededor de todo el bucle for item in c.query(wql): para permitir que cada hilo realice una mayor cantidad de trabajo antes de liberar el candado.

print no es segura para subprocesos Utilice el módulo de logging lugar (que es):

 import logging import threading import time FORMAT = '[%(levelname)s] (%(threadName)-10s) %(message)s' logging.basicConfig(level=logging.DEBUG, format=FORMAT) file_handler = logging.FileHandler('results.log') file_handler.setFormatter(logging.Formatter(FORMAT)) logging.getLogger().addHandler(file_handler) def worker(): logging.info('Starting') time.sleep(2) logging.info('Exiting') t1 = threading.Thread(target=worker) t2 = threading.Thread(target=worker) t1.start() t2.start() 

Salida (y contenido de results.log ):

 [INFO] (Thread-1 ) Starting [INFO] (Thread-2 ) Starting [INFO] (Thread-1 ) Exiting [INFO] (Thread-2 ) Exiting 

En lugar de usar el nombre predeterminado ( Thread-n ), puede establecer su propio nombre usando el argumento de palabra clave del name , que luego la directiva de formato %(threadName) usará:

 t = threading.Thread(name="My worker thread", target=worker) 

(Este ejemplo fue adaptado de un ejemplo del excelente artículo de Doug Hellmann sobre el módulo de threading )

Para otra solución, use un Pool para calcular los datos, devolviéndolos al proceso principal. Este padre luego escribe todos los datos en un archivo. Como solo hay un proceso que se escribe en el archivo a la vez, no es necesario realizar un locking adicional.

Tenga en cuenta que lo siguiente utiliza un conjunto de procesos , no hilos . Esto hace que el código sea mucho más simple y sencillo que armar algo usando el módulo de threading . (Hay un objeto ThreadPool , pero no está documentado).

fuente

 import glob, os, time from multiprocessing import Pool def filesize(path): time.sleep(0.1) return (path, os.path.getsize(path)) paths = glob.glob('*.py') pool = Pool() # default: proc per CPU with open("results.txt", 'w+') as dataf: for (apath, asize) in pool.imap_unordered( filesize, paths, ): print >>dataf, apath,asize 

salida en results.txt

 zwrap.py 122 usercustomize.py 38 tpending.py 2345 msimple4.py 385 parse2.py 499