[Programación de subprocesos múltiples de Python - módulo de subprocesos] - Serie de artículos de subprocesos múltiples de Python (2)


prefacio

Artículo anteriorIntroducción al módulo de subprocesos Portal:

https://blog.csdn.net/youngwyj/article/details/124720041

La sincronización de subprocesos es un concepto importante en subprocesos múltiples.Cuando varios subprocesos necesitan compartir datos, si no se utiliza la sincronización de subprocesos, los datos no estarán sincronizados.
Hay dos métodos para lograr la sincronización de subprocesos, el bloqueo de subprocesos y la variable de condición Condición.


1. Bloqueo de rosca

1. Bloqueo de bloqueo

El bloqueo Lock en el módulo de roscado es el mismo que el bloqueo en el módulo _thread.
Ejemplo:

import threading
import time

num = 0
lock = threading.Lock()  #申请线程锁

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        global num  #声明全局变量num

        # lock.acquire()  #申请线程锁

        print('子线程' + self.getName() + '开始:' + str(time.time()))
        while num < 5:
            time.sleep(2)  
            print(self.getName(),'num:',num)
            num += 1
        #休眠2s
        print('子线程' + self.getName() + '结束:' + str(time.time()))

        # lock.release()  #释放线程锁
        
        return super().run()

if __name__ == '__main__':

    print('主线程开始:%s'%(str(time.time())))
    thread1 = threadTest()
    thread1.setName('Thread-1') #设置线程名称
    thread2 = threadTest()
    thread2.setName('Thread-2') #设置线程名称    
    thread1.start()  #启动线程
    thread2.start()  #启动线程
    time.sleep(1)
    thread1.join()
    thread2.join()
    print('主线程已结束:%s'%(str(time.time())))

resultado de la operación:

主线程开始:1652803641.5234373
子线程Thread-1开始:1652803641.5236645
子线程Thread-2开始:1652803641.5238614
Thread-2 num: 0
Thread-1 num: 0
Thread-2 num: 2
Thread-1 num: 3
Thread-2 num: 4
子线程Thread-2结束:1652803647.5305896
Thread-1 num: 5
子线程Thread-1结束:1652803647.5308123
主线程已结束:1652803647.531019

Se puede ver que cuando no se usa el subproceso de bloqueo, el subproceso 1 y el subproceso 2 tienen confusión sobre la operación numérica.
Elimine los comentarios de las dos líneas anteriores de código lock.acquire() lock.release() y agregue el bloqueo de subprocesos.
Los resultados de ejecución son los siguientes: Puede ver que no habrá confusión como la anterior.

主线程开始:1652804037.7551372
子线程Thread-1开始:1652804037.7553797
Thread-1 num: 0
Thread-1 num: 1
Thread-1 num: 2
Thread-1 num: 3
Thread-1 num: 4
子线程Thread-1结束:1652804047.7664511
子线程Thread-2开始:1652804047.766612
子线程Thread-2结束:1652804047.7667737
主线程已结束:1652804047.7669005

2. Bloqueo RLock

El bloqueo de RLock, también conocido como bloqueo recursivo, se diferencia del bloqueo de bloqueo en que el bloqueo de bloqueo solo permite una aplicación en el mismo subproceso; de lo contrario, el subproceso entrará en interbloqueo, pero RLock permite múltiples llamadas en el mismo subproceso.
Código de ejemplo para interbloqueo usando Lock lock:

import threading
import time

print('主线程开始:%s'%(str(time.time())))
lock = threading.Lock()

lock.acquire()    #申请线程锁
print(threading.enumerate())

lock.acquire()    #再次申请线程锁,产生了死锁
print(threading.enumerate())

lock.release()
lock.release()
print('主线程结束:%s'%(str(time.time())))

resultado de la operación:

主线程开始:1652804393.5089679
[<_MainThread(MainThread, started 140384603543360)>]
^Z					#此处为我在终端中主动杀死了线程,并非程序自己结束
[1]+  已停止

El uso del bloqueo RLock no provocará un código de ejemplo de interbloqueo:

import threading
import time

print('主线程开始:%s'%(str(time.time())))
lock = threading.RLock()

lock.acquire()    #申请线程锁
print(threading.enumerate())

lock.acquire()    #再次申请线程锁,不会产生死锁
print(threading.enumerate())

lock.release()
lock.release()
print('主线程结束:%s'%(str(time.time())))

resultado de la operación:

主线程开始:1652804609.3881009
[<_MainThread(MainThread, started 140639696934720)>]
[<_MainThread(MainThread, started 140639696934720)>]
主线程结束:1652804609.3881621

De lo anterior, puede ver la diferencia entre Lock y RLock
Tenga en cuenta que los bloqueos de subprocesos deben aparecer en pares

Dos, la variable de condición Condición

La condición es un bloqueo más avanzado en python 3. Además de las funciones de adquisición () y liberación () similares a los bloqueos de subprocesos, también proporciona las siguientes funciones.

función ilustrar
esperar() suspender el hilo
notificar() Activar un subproceso suspendido para ejecutar
notificar a todos () Despierta todos los subprocesos para que se ejecuten

Nota: El bloqueo debe obtenerse antes de usar el subproceso; de lo contrario, se lanzará una excepción RuntimeError.

Se puede entender que Condition proporciona un mecanismo de comunicación de subprocesos múltiples. Si el subproceso 1 necesita datos, el subproceso 1 se bloqueará y esperará. El subproceso 2 produce datos. Después de que el subproceso 2 produce datos y notifica al subproceso 1, el subproceso 1 puede ir a obtener los datos.

El siguiente es un código de muestra para simular idiom Solitaire usando la variable de condición Condición:

import threading
import time

class Man1(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self,lock) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(Man1,self).__init__()  #初始化super()内的必须与类名一样
        self.lock = lock

    def run(self):
        self.lock.acquire()  #申请锁
        print('子线程' + self.getName() + '为所欲为')

        self.lock.wait()   #挂起线程,等待回答
        print('子线程' + self.getName() + '逼上梁山')
        self.lock.notify()  #运行挂起的线程

        self.lock.wait()
        print('子线程' + self.getName() + '尽力而为')
        self.lock.notify()

        self.lock.release()

class Man2(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self,lock) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(Man2,self).__init__()  #初始化super()内的必须与类名一样
        self.lock = lock

    def run(self):
        self.lock.acquire()

        self.lock.notify()   #唤醒对方线程
        print('子线程' + self.getName() + '为法自弊')
        self.lock.wait()   #挂起线程,等待回答
        
        self.lock.notify()  
        print('子线程' + self.getName() + '山穷水尽')
        self.lock.wait()
        
        self.lock.notify()       
        print('子线程' + self.getName() + '为所欲为')

        self.lock.release()

if __name__ == '__main__':
    lock = threading.Condition()
    man1 = Man1(lock)
    man2 = Man2(lock)
    man1.setName('Thread-1') #设置线程名称
    man2.setName('Thread-2') #设置线程名称   
    print('成语接龙开始:')
    man1.start()
    man2.start()

resultado de la operación:

成语接龙开始:
子线程Thread-1为所欲为
子线程Thread-2为法自弊
子线程Thread-1逼上梁山
子线程Thread-2山穷水尽
子线程Thread-1尽力而为
子线程Thread-2为所欲为

Se puede ver que bajo el control de la variable de condición, los dos hilos se ejecutan en secuencia hasta el final.

Supongo que te gusta

Origin blog.csdn.net/youngwyj/article/details/124833126
Recomendado
Clasificación