Usar objetos Lock y RLock
Si varios subprocesos modifican conjuntamente una determinada información, pueden producirse resultados impredecibles. Para garantizar la precisión de los datos, es necesario modificar varios subprocesos sincrónicamente. En el programa Python, use el objeto Lock y RLock
Se puede lograr una sincronización de subprocesos simple. Ambos objetos tienen métodos de adquisición y liberación. Para los datos que requieren que funcione solo un subproceso a la vez, puede colocar su operación entre los métodos de adquisición y liberación.
La ventaja de los subprocesos múltiples es que puede ejecutar múltiples tareas al mismo tiempo (sentirse así), pero cuando los subprocesos necesitan compartir datos, puede haber problemas con los datos que no están sincronizados. El siguiente código demuestra el uso de RLock para lograr la sincronización de subprocesos.
import threading import time class mt (threading.Thread): def run (self): global x lock.acquire () for i in range (5): x + = 10 time.sleep (1) print (x) lock.release () x = 0 lock = threading.RLock () def main (): thrs = [] para el elemento en el rango (8): thrs.append (mt ()) para el elemento en thrs: item.start () if __name__ = = '__main__': main ()
En el ejemplo anterior, se personaliza una clase de subproceso mt con un bloqueo para acceder a la variable global x, y se inicializan 8 subprocesos en la función principal main () para modificar x. Al mismo tiempo, solo un subproceso puede operar en x para realizar el efecto Como sigue:
50, 100, 150 ... En el programa Python, si desea hacer que el objeto variable sea seguro en un entorno de subprocesos múltiples, puede usar el objeto Lock en subprocesos para resolverlo. El siguiente código demuestra el proceso de bloqueo de la sección crítica.
Importar clase de subprocesos ShareCounter: def __init __ (self, initial_value = 0): self._value = initial_value self._value_lock = threading.Lock () def incr (self, delta = 1): with self._value_lock: self._value + = delta def decr (self, delta = 1): con self._value_lock: self._value - = delta def test (c): para n en rango (10000): c.incr () para n en rango (10000): c. decr () if __name__ == '__main__': c = ShareCounter () t1 = threading.Thread (target = test, args = (c,)) t2 = threading.Thread (target = test, args = (c,)) t3 = threading.Tread (target = test, args = (c,)) t1.start () t2.start () t3.start () print ('Prueba de ejecución') t1.join () t2.join () t3 .join () afirmar c._value == 0 print ('Locks good!', c._value) # 0
En el código anterior, cuando se usa la instrucción with, el objeto Lock puede garantizar que se produzca un comportamiento mutuamente exclusivo, es decir, solo se ejecuta un subproceso a la vez para ejecutar la instrucción with.
Usar objetos de condición
En Python, puede usar el objeto Condición para procesar datos solo después de que se activen ciertos eventos o cuando se cumplan ciertas condiciones. El propósito del objeto Condición es admitir problemas complejos de sincronización de subprocesos.
La condición generalmente se asocia con un bloqueo. Cuando necesite compartir un bloqueo en varias condiciones, puede pasar una instancia de Lock / RLock, de lo contrario, generará automáticamente un bloqueo. El siguiente código usará
Conditon implementa un juego de escondite: 1. Cuando comienza el juego, Seeker primero se cubre los ojos para gobernar a Hider, 2. Después de que Hider recibe la notificación, se esconde y luego notifica a Seeker que puede encontrarla.
importación de subprocesos, clase de tiempo Hider (threading.Thread): def __init __ (self, cond, name): super (Hider, self) .__ init __ () # Es necesario ejecutar primero la función de inicialización de la clase padre, de lo contrario el nombre se sobrescribirá por self.cond = cond self.name = name def run (self): time.sleep (1) # Asegúrese de que Seeker primero ejecute self.cond.acquire () # 3, obtenga el bloqueo, realice la siguiente operación print ("He cerrado los ojos ¡Eso es todo! ") Self.cond.notify () # Notificar a otro para desbloquear y suspender self.cond.wait () print (self.name,": Te he encontrado ") self.cond.notify () self .cond.release () print ( self.name , ': I won') class Seeker (threading.Thread): def __init __ (self, cond, name): super (Seeker, self) .__ init __ () # Necesita ejecutar primero la función de inicialización de la clase padre, de lo contrario el nombre será Estar cubierto self.cond = cond self.name = name def run (self): self.cond.acquire () # 1, obtenga el bloqueo self.cond.wait () # 2, libere la ocupación del bloqueo, mientras el hilo se cuelga, sepa notificar () Y vuelva a ocupar la impresión de bloqueo (self.name, ": lo he ocultado, búscame rápidamente") self.cond.notify () self.cond.wait () self.cond.release () print (self.name, ": Encontrado por usted, hey") cond = threading.Condition () seeker = Seeker (cond, 'seeker') hider = Hider (cond, 'hider') seeker.start () hider.start () "" "¡ He cerrado los ojos! Buscador: lo he escondido, encuéntrame rápidamente oculto: te he encontrado Buscador: te he encontradoHe encontrado a tu oculto: gané buscador: Encontrado por usted, oye "" "
Usar objetos de semáforo y semáforo limitado
En Python, puede usar Semaphore y BoundedSemaphore para controlar el contador en un sistema de señal multiproceso.
1. Semáforo: subprocesos de clase. El semáforo es un semáforo que controla el acceso a recursos públicos o secciones críticas. El semáforo mantiene un contador que especifica el número de subprocesos que pueden acceder simultáneamente a los recursos o ingresar a la sección crítica, cada vez
Un hilo recibe la señal, el contador es -1, si el contador es 0, otros hilos dejan de acceder.
importación de subprocesos, diversión de def. de tiempo (semáforo, num): semaphore.acquire () print ("降龙十八掌 , 发出% d 掌"% num) time.sleep (3) semaphore.release () if __name__ == ' __main__ ': semaphore = threading.Semaphore (2) para num in range (4): t = threading.Thread (target = fun, args = (semaphore, num)) t.start ()
Después de la ejecución, los subprocesos 0 y 1 se ejecutan al mismo tiempo, y 2, 3 se ejecutan después de 3 segundos.
2. BoundedSemaphore: verificará el valor del contador interno y se asegurará de que no sea mayor que el valor inicial. Si lo excede, se generará un ValueError, que a menudo se utiliza para proteger el acceso restringido a los recursos.
Usar objeto de evento
En Python, un objeto de evento es uno de los mecanismos de comunicación más simples entre hilos, un hilo puede activar otros hilos que esperan en un objeto de evento. La clase de implementación del objeto Event es threading.
Esta es una clase que implementa un objeto de evento. Un evento gestiona un indicador. El indicador se puede establecer en verdadero por el método set () o restablecer en falso por el método clear (). El método wait () bloquea hasta que el indicador sea verdadero.
El valor inicial es falso.
importación de subprocesos, evento de tiempo = subprocesamiento. Evento () def func (): # print ("% s wait for event ..."% threading.currentThread (). getName ()) # event.wait (timeout) 阻塞 线程 ,直到 evento 对象 内部 标 实 位 为 Verdadero , 或 超时 event.wait () print ("% s recv event".% Threading.currentThread (). GetName ()) t1 = threading.Thread (target = func) t2 = threading .Thread (target = func) t1.start () t2.start () time.sleep (2) print ("MainTread set event") event.set () # 将 标识 位 改为 True "" " Thread-1 wait para evento ... Thread-2 espera para evento ... MainTread establece evento Thread-2 recv event. Thread-1 recv event. "" "
Usar objeto de temporizador
Temporizador: Temporizador, utilizado para llamar a un método después de un tiempo específico, la acción de temporizador correspondiente puede cancelarse mediante la función cancel ().
import threading def func (): print ("ping") timer = threading.Timer (5, func) timer.start ()