Cómo implementar un proceso en Python
Para aprovechar al máximo los recursos de la CPU de múltiples núcleos, en la mayoría de los casos es necesario utilizar múltiples procesos en Python. Python proporciona el paquete de multiprocesamiento para implementar múltiples procesos. El multiprocesamiento admite la sincronización y la comunicación entre procesos secundarios y procesos, y proporciona componentes como proceso, cola, canalización y bloqueo.
Abrir un proceso hijo
El multiprocesamiento proporciona la clase Proceso para generar instancias de proceso
Proceso([grupo [, destino [, nombre [, args [, kwargs] ]]]]])1
La agrupación de grupos no se utiliza realmente
el objetivo representa el objeto que llama. Puede pasar el nombre del método
args. representa el El objeto que llama proporciona parámetros en forma de tuplas. Por ejemplo, el objetivo es la función a y tiene dos parámetros m, n. Entonces los parámetros son args=(m, n)
kwargs. el nombre del Diccionario del objeto que llama es un alias, lo que equivale a darle un nombre a este proceso.
Primero tomemos un pequeño ejemplo: # -*- codificación:utf-8 -* -desde el proceso de importación multiprocesamiento, Poolimport osimport timedef run_proc(wTime):
n = 0
while n < 3: print "subProcess %s run", % os.getpid() , "{0}" .format(time.ctime()) #Obtener el número de proceso actual y el tiempo de ejecución
time.sleep(wTime) #Esperar (dormir)
n += 1if __name__ == "__main__":
p = Proceso(target=run_proc, args=(2,)) ?#Aplicar para proceso hijo
p.start() #Ejecutar proceso p>
print "Proceso principal en ejecución. El subProceso es ", p.pid print "Fin del proceso principal,{0}".format(time.ctime())12345678910111213141516171819
Resultados de la ejecución: p>
¿El proceso principal se ejecuta? Lun 27 de marzo 11: 20:21 2017?
SubProceso 30196 ejecutado, Lun 27 de marzo 11:20:23 2017?
SubProceso 30196 ejecutado, Lun 27 de marzo 11:20:25 2017
Según los resultados de la ejecución, se puede ver que el proceso hijo todavía se está ejecutando después de que finaliza el proceso padre, lo que puede provocar un proceso zombie.
Normalmente, cuando el proceso hijo finaliza, notificará al proceso padre, borrará la memoria que ocupa y dejará su propia información de salida en el kernel. Cuando el proceso padre se entera de que el proceso hijo ha terminado, recuperará la información de salida del proceso hijo del kernel. Sin embargo, si el proceso padre termina antes que el proceso hijo, esto puede hacer que la información de salida del proceso hijo permanezca en el kernel y el proceso hijo se convierta en un proceso zombie. Cuando se acumula una gran cantidad de procesos zombies, se ocupará espacio en la memoria.
¿Hay alguna forma de evitar procesos zombies? ?
Aquí introducimos un atributo del proceso, deamon. Cuando su valor es VERDADERO, su proceso padre finaliza y el proceso también finaliza directamente (incluso si no ha terminado de ejecutarse). ?
Así que agregue p.deamon = true al programa anterior y vea el efecto. # -*- codificación:utf-8 -*-desde proceso de importación multiprocesamiento, Poolimport osimport timedef run_proc(wTime):
n = 0
while n < 3: print "subProcess %s ejecutar", % os.getpid(), "{0}".format(time.ctime())
time.sleep(wTime)
n += 1if __name__ == "__main__":
p = Proceso(target=run_proc, args=(2,))
p.daemon = True #Agregar demonio
p.start() print "Proceso principal en ejecución. El subProceso es ", p.pid print "Fin del proceso principal,{0}".format(time.ctime())1234567891011121314151617181920
Resultado de la ejecución:
¿El proceso principal se está ejecutando. El subproceso es 31856?
Fin del proceso principal, lunes 27 de marzo 11:40:10 2017
Este es el problema nuevamente, el subproceso tiene no se ha ejecutado, lo cual no es el resultado esperado.
¿Hay alguna forma de finalizar el proceso principal una vez que el proceso secundario haya terminado de ejecutarse? ?
Aquí se presenta el método p.join(), que hace que el proceso principal ejecute el código posterior después de que finaliza la ejecución del proceso secundario # -*- coding:utf-8 -*-. del proceso de importación multiprocesamiento, Poolimport osimport timedef run_proc(wTime):
n = 0
while n < 3: print "subProcess %s run", % os.getpid(), "{0}". formato(time.ctime())
time.sleep(wTime)
n += 1if __name__ == "__main__":
p = Proceso( target=run_proc, args=(2,))
p.daemon = True
p.start()
p. join() #Método de unión
print "Proceso principal en ejecución. El subproceso es ", p.pid print "Fin del proceso principal,{0}".format(time.ctime())123456789101112131415161718192021
Resultado de la ejecución:
¿ejecución del subproceso 32076, lunes 27 de marzo a las 11:46:07 de 2017?
ejecución del subproceso 32076, lunes 27 de marzo a las 11:46:09 de 2017?
p>¿Se ejecuta el subproceso 32076, lunes 27 de marzo 11:46:11 de 2017?
¿Se ejecuta el proceso principal? ¿El subproceso es 32076?
Fin del proceso principal, lunes 27 de marzo 11: 46:13 2017
De esta manera, todos los procesos se pueden ejecutar sin problemas.
Definir procesos en clases
Al heredar la clase Proceso, puede personalizar la clase de proceso e implementar el método de ejecución. La instancia p llama automáticamente al método de ejecución cuando se llama a p.start().
?
Como sigue: # -*- coding:utf-8 -*-from proceso de importación multiprocesamiento, Poolimport osimport timeclass Myprocess(Process):
def __init__(self, wTime) :
Process.__init__(self)
self.wTime = wTime def run(self):
n = 0
mientras n < 3: imprimir "subProceso %s ejecución", % os.getpid(), "{0}".format(time.ctime())
time.sleep(self.wTime) p >
n += 1if __name__ == "__main__":
p = Miproceso(2)
p.daemon = True
p. start () #Llamar automáticamente al método de ejecución
p.join() print "Proceso principal en ejecución. El subproceso es ", p.pid print "Fin del proceso principal,{0}".format(time.ctime () )12345678910111213141516171819202122232425262728
El resultado de la ejecución es el mismo que en el ejemplo anterior.
Crear múltiples procesos
Muchas veces el sistema necesita crear múltiples procesos para mejorar la utilización de la CPU. Cuando el número es pequeño, puede generar manualmente instancias de proceso una por una. Cuando hay una gran cantidad de procesos, es posible utilizar bucles, pero esto requiere que los programadores administren manualmente la cantidad de procesos concurrentes en el sistema, lo que a veces es problemático. En este momento, el grupo de procesos Pool puede desempeñar su función. Puede limitar la cantidad de procesos simultáneos pasando parámetros. El valor predeterminado es la cantidad de núcleos de la CPU.
?
Vaya directamente al ejemplo: # -*- coding:utf-8 -*-from multiprocesamiento import Process, Poolimport os, timedef run_proc(name): ##Defina una función para llamar al proceso p >
para i en rango(5):
time.sleep(0.2) #Dormir durante 0.2 segundos
print 'Ejecutar proceso hijo %s (%s)' % (name, os.getpid())#Se tarda 1 segundo en ejecutar esta función una vez si __name__ =='__main__': #Ejecutar el proceso principal
print 'Ejecutar el proceso principal (%s) .' % (os.getpid())
mainStart = time.time() #Registrar la hora en que se inicia el proceso principal
p = Pool(8) #¿Abrir un? grupo de procesos
para i en rango(16): #Abrir 14 procesos
p.apply_async(run_proc,args=('Proceso'+str(i),))#Each proceso Se llama a la función run_proc
#args representa los parámetros pasados a la función.
print 'Esperando que todos los subprocesos hayan finalizado...'
p.close() #Cerrar el grupo de procesos
p.join() ?#Esperando para abrir Después de que se hayan ejecutado todos los procesos, el proceso principal continuará ejecutándose
print 'Todos los subprocesos completados'
mainEnd = time.time() ?#Registrar la hora de finalización del proceso principal
p>
print 'Todo el proceso ejecutó %0.2f segundos.' % (mainEnd-mainStart)?#Tiempo de ejecución del proceso principal 123456789101112131415161718192021222324
Resultado de la ejecución: ?
Parte inicial
Ejecutar el proceso principal (30920).?
¿Esperando que se completen todos los subprocesos...?
Ejecutar el proceso secundario. ¿Proceso0 (32396)?
¿Ejecutar el proceso hijo Proceso3 (25392)?
¿Ejecutar el proceso hijo Proceso1 (28732)?
Ejecutar el proceso hijo Proceso2 (32436)
Última parte:
p>
¿Ejecutar el proceso hijo Process15 (25880)?
¿Todos los subprocesos terminados?
Todos los procesos al final 2,49 segundos.
Instrucciones relacionadas:
El límite de la cantidad de procesos concurrentes en el grupo de procesos aquí es 8, y se generarán 16 procesos cuando el programa se esté ejecutando. El grupo administrará automáticamente la cantidad de procesos simultáneos en el sistema y los procesos restantes esperarán en la cola.
La razón para limitar el número de procesos concurrentes es que cuantos más procesos concurrentes haya en el sistema, mejor. Demasiados procesos concurrentes pueden hacer que la CPU dedique la mayor parte de su tiempo a la programación de procesos en lugar de realizar cálculos efectivos.
Cuando se utiliza tecnología de concurrencia multiproceso, en lo que respecta a un único procesador, su ejecución de procesos es en serie. Sin embargo, es impredecible qué proceso obtendrá recursos de la CPU y se ejecutará en un momento específico (por ejemplo, al comienzo del resultado de la ejecución, el orden de ejecución de cada proceso es incierto), lo que refleja la naturaleza asincrónica del proceso.
Si un solo programa ejecuta la función run_proc 14 veces, tomará al menos 16 segundos. A través de la concurrencia del proceso, solo toma 2,49 segundos, lo que muestra las ventajas de la concurrencia.