English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Recientemente, al aprender la programación concurrente en Python, hice un resumen de los procesos múltiples, hilos múltiples, asíncronos y coroutines.
Primero, los hilos multitudinarios
Los hilos multitudinarios permiten que existan múltiples controladores dentro de un proceso, para que múltiples funciones estén activas al mismo tiempo, permitiendo que las operaciones de múltiples funciones se ejecuten simultáneamente. Incluso en una computadora con un solo CPU, se puede lograr el efecto de ejecución simultánea de múltiples hilos mediante la continua conmutación entre instrucciones de diferentes hilos.
Los hilos multitudinarios equivalen a un sistema concurrente (concurrente). Los sistemas concurrentes generalmente ejecutan múltiples tareas al mismo tiempo. Si múltiples tareas pueden compartir recursos, especialmente cuando se escriben en un variable al mismo tiempo, se debe resolver el problema de sincronización, como el sistema de venta de boletos de tren de múltiples hilos: dos instrucciones, una instrucción verifica si los boletos están agotados, y otra instrucción, múltiples ventanas venden boletos al mismo tiempo, puede ocurrir que se vendan boletos inexistentes.
En situaciones de concurrencia, el orden de ejecución de las instrucciones se decide por el núcleo. Dentro del mismo hilo, las instrucciones se ejecutan en el orden en que se escriben, pero es difícil decir cuál se ejecutará primero entre las instrucciones de diferentes hilos. Por lo tanto, debe considerarse el problema de la sincronización de múltiples hilos. La sincronización (synchronization) es permitir que solo una línea de código acceda a un recurso en un período de tiempo determinado.
1Módulo thread
2Módulo threading
threading.Thread crea un hilo.
Para que el juicio de si hay billetes restantes y la venta de billetes se realicen con un mutex, de modo que no se cause que un hilo juzgue que no hay billetes restantes y que otro hilo ejecute la operación de venta de billetes.
#! /usr/bin/python #-* coding: utf-8 -* # __author__ ="tyomcat" import threading import time import os def booth(tid): global i global lock while True: lock.acquire() if i!=0: i=i-1 print "Ventana:", tid,", número de boletos restantes:", i time.sleep(1) else: print "Thread_id", tid, "No more tickets" os._exit(0) lock.release() time.sleep(1) i = 100 lock=threading.Lock() for k in range(10) new_thread = threading.Thread(target=booth, args=(k,)) new_thread.start()
II. Coroutines (también conocidas como microhilos, fibras)
Las coroutines, a diferencia del ajuste de prioridad preempresivo de los hilos, son de ajuste colaborativo. Las coroutines también son de un solo hilo, pero permiten que lo que originalmente requeriría el uso de asincronía+El código no humano escrito en modo callback puede escribirse de manera que parezca sincrónico.
1Las coroutines en python pueden implementarse mediante generadores (generator).
Primero, es necesario tener una comprensión sólida de los generadores y yield.
Llamar a una función python común generalmente comienza desde la primera línea de código de la función y termina con la instrucción return, una excepción o la ejecución de la función (también se puede considerar que se devuelve implícitamente None).
Una vez que la función devuelve el control al llamador, significa que todo ha terminado. A veces, se puede crear una función que genere una secuencia para “guardar su trabajo”, lo que es un generador (una función que utiliza la palabra clave yield).
Poder “generar una secuencia” se debe a que la función no regresa como se suele entender. El significado implícito de return es que la función está devolviendo el control a la ubicación donde se llamó la función. Mientras que el significado implícito de yield es que la transferencia de control es temporal y voluntaria, nuestra función recuperará el control en el futuro.
Vamos a ver el productor/Ejemplo de consumidor:
#! /usr/bin/python #-* coding: utf-8 -* # __author__ ="tyomcat" import time import sys # Productor def produce(l): i=0 while 1: if i < 10: l.append(i) yield i i=i+1 time.sleep(1) else: return # Consumidor def consume(l): p = produce(l) while 1: try: p.next() while len(l) > 0: print l.pop() except StopIteration: sys.exit(0) if __name__ == "__main__": l = [] consume(l)
Cuando el programa ejecuta produce(yield i), devuelve un generador y se detiene la ejecución. Cuando llamamos a p.next() en custom, el programa vuelve a la ejecución de produce(yield i), y luego se agrega un elemento a l, luego imprimimos l.pop(), hasta que p.next() provoca la excepción StopIteration.
2、Stackless Python
3、módulo greenlet
La implementación basada en greenlet tiene un rendimiento apenas inferior al de Stackless Python, aproximadamente un tercio más lento que Stackless Python, y casi una orden de magnitud más rápido que otras soluciones. De hecho, greenlet no es un mecanismo de concurrencia verdadero, sino que realiza la transición entre diferentes bloques de código de ejecución de diferentes funciones dentro de la misma línea de tiempo, implementando "tú ejecutas un rato, yo ejecuto un rato", y debe especificarse cuándo y a dónde hacer la transición en la transición
4、módulo eventlet
Tres, multiprocesamiento
1、subprocess (paquete)
En Python, a través del paquete subprocess, se puede crear un proceso hijo y ejecutar un programa externo
Al llamar a los comandos del sistema, el módulo os es el primero en considerarse. Se utilizan os.system() y os.popen() para realizar operaciones. Sin embargo, estos comandos son demasiado simples y no pueden completar algunas operaciones complejas, como proporcionar entrada a los comandos en ejecución o leer la salida de los comandos, determinar el estado de ejecución del comando, gestionar la ejecución paralela de múltiples comandos, etc. En este caso, el comando Popen de subprocess puede completar eficazmente las operaciones necesarias
>> import subprocess >> command_line=raw_input() ping -c 10 www.baidu.com >> args=shlex.split(command_line) >> p=subprocess.Popen(args)
Utilizar subprocess.PIPE para conectar los entradas y salidas de múltiples subprocesos, formando un tubo (pipe):
import subprocess child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) child2 = subprocess.Popen(["wc"], stdin=child1.stdout, stdout=subprocess.PIPE) out = child2.communicate() print(out)
método communicate() lee datos de stdout y stderr, e introduce en stdin.
2、multiprocesamiento (paquete multiprocessing)
(1)、multiprocessing paquete es el paquete de gestión de multiprocesos en Python. Al igual que threading.Thread, puede utilizar el objeto multiprocessing.Process para crear un proceso.
El pool de procesos (Process Pool) puede crear varios procesos.
apply_async(func,args) extraer un proceso del pool de procesos para ejecutar func, args son los argumentos de func. Devolverá un objeto AsyncResult, puedes llamar al método get() del objeto para obtener el resultado.
close() el pool de procesos ya no creará nuevos procesos
join() esperar a que todos los procesos del pool de procesos finalicen. Es necesario llamar primero al método close() del Pool antes de llamar a join().
#! /usr/bin/env python # -*- coding:utf-8 -*- # __author__ == "tyomcat" # "Mi computadora tiene4número de cpu" from multiprocessing import Pool import os, tiempo def larga_tarea_tiempo(name): print 'Ejecutar tarea %s (%s)...' % (name, os.getpid()) start = time.time() time.sleep(3) end = time.time() print 'Tarea %s se ejecuta %0.2f segundos.' % (name, (end - start)) if __name__=='__main__': print 'Proceso padre %s.' % os.getpid() p = Pool() for i in range(4) p.apply_async(long_time_task, args=(i,)) print 'Esperando a que todos los subprocesos finalicen...' p.close() p.join() print 'Todos los subprocesos finalizados.'
(2)、多进程共享资源
A través de la memoria compartida y el objeto Manager: usar un proceso como servidor, establecer un Manager para almacenar realmente los recursos.
Los otros procesos pueden acceder al Manager mediante parámetros o según la dirección, establecer una conexión y operar en los recursos del servidor.
#! /usr/bin/env python # -*- coding:utf-8 -*- # __author__ == "tyomcat" from multiprocessing import Queue,Pool import multiprocessing,time,random def write(q): for value in ['A','B','C','D']: print "Put %s to Queue!" % value q.put(value) time.sleep(random.random()) def read(q,lock): while True: lock.acquire() if not q.empty(): value=q.get(True) print "Get %s from Queue" % value time.sleep(random.random()) else: break lock.release() if __name__ == "__main__": manager=multiprocessing.Manager() q=manager.Queue() p=Pool() lock=manager.Lock() pw=p.apply_async(write,args=(q,)) pr=p.apply_async(read,args=(q,lock)) p.close() p.join() print print "Todos los datos se han escrito y leído"
Cuatro, asincrónico
Ya sea hilo o proceso, utilizan el sistema de conteo sincrónico, cuando ocurre un bloqueo, el rendimiento se reduce significativamente, no se puede aprovechar plenamente el potencial del CPU, desperdiciando la inversión en hardware, y más importante, causando la rigidez del módulo de software, la acoplamiento estricto, no se puede cortar, lo que no es ventajoso para la expansión y el cambio futuro.
Ya sea proceso o hilo, cada bloqueo y cambio requiere caer en la llamada al sistema (system call), primero permitir que el CPU corra el programa de planificación del sistema operativo, y luego que el programa de planificación decida qué proceso (hilo) debe correr. Además, entre varios hilos, cuando se accede a código mutuo, se deben agregar bloques de exclusión mutua.
Actualmente, la mayoría de los servidores asincrónicos populares se basan en el modelo de eventos (como nginx).
En el modelo de eventos asincrónicos, se convierten las operaciones que causarán bloqueo en operaciones asincrónicas, la línea principal es responsable de iniciar esta operación asincrónica y manejar el resultado de esta operación asincrónica. Dado que todas las operaciones de bloqueo se convierten en operaciones asincrónicas, teóricamente la mayoría del tiempo de la línea principal se dedica a manejar tareas de cálculo reales, lo que reduce el tiempo de调度 de múltiples hilos, por lo que este modelo generalmente tiene un mejor rendimiento.
Esto es todo el contenido de este artículo, espero que sea útil para su aprendizaje y que todos nos apoyen en el tutorial de alarido.
Declaración: El contenido de este artículo se obtiene de la red, es propiedad del autor original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio web no posee derechos de propiedad, no se ha realizado edición humana y no asume responsabilidad por responsabilidades legales relacionadas. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante.3Declaración: El contenido de este artículo se obtiene de la red, es propiedad del autor original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio web no posee derechos de propiedad, no se ha realizado edición humana y no asume responsabilidad por responsabilidades legales relacionadas. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante, una vez confirmado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.