一、引言
在Python多线程编程中,咱们经常须要解决多个线程同时访问共享数据的状况。为了避免数据在多线程之间呈现抵触,咱们须要对线程进行同步。本文将具体介绍Python中的线程同步的几种罕用办法:锁(Lock),递归锁(RLock),条件变量(Condition),信号量(Semaphore),事件(Event),以及屏障(Barrier)。
二、锁(Lock)
Python的threading
模块提供了锁(Lock)作为最根本的线程同步机制。锁有两种状态,"locked"和"unlocked"。当多个线程要访问共享数据时,它们必须先获取锁,拜访数据后再开释锁。只有一个线程能够获取锁,其余线程必须期待,直到锁被开释。
以下是一个应用锁的例子:
import threading# 创立一个锁lock = threading.Lock()def worker(): # 获取锁 lock.acquire() try: # 访问共享数据 print("Thread is working...") finally: # 开释锁 lock.release()# 创立两个线程thread1 = threading.Thread(target=worker)thread2 = threading.Thread(target=worker)# 启动线程thread1.start()thread2.start()# 期待所有线程完结thread1.join()thread2.join()
在这个例子中,两个线程必须在访问共享数据之前获取锁。因而,它们不能同时访问共享数据,防止了数据抵触。
三、递归锁(RLock)
递归锁(RLock)是一种能够被同一个线程屡次获取的锁。它与一般锁的区别在于,如果一个线程曾经获取了一个递归锁,它能够再次获取这个锁,而不会导致线程阻塞。这在某些须要在同一个线程中屡次获取锁的状况下十分有用。
以下是一个应用递归锁的例子:
import threading# 创立一个递归锁rlock = threading.RLock()def worker(): # 获取锁 rlock.acquire() try: # 再次获取锁 rlock.acquire() try: # 访问共享数据 print("Thread is working...") finally: # 第一次开释锁 rlock.release() finally: # 第二次开释锁 rlock.release()# 创立两个线程thread1 = threading.Thread(target=worker)thread2 = threading.Thread(target=worker)# 启动线程thread1.start()thread2.start()# 期待所有线程完结thread1.join()thread2.join()
在这个例子中,同一个线程能够屡次获取同一个递归锁。这是通过在每次获取锁时减少一个计数器,每次开释锁时缩小一个计数器来实现的。只有当计数器的值为零时,锁才会真正的被开释,这样其余线程才有可能获取到这个锁。
递归锁能够解决一些简单的锁需要,例如一个函数在递归调用时须要获取锁,或者一个线程须要在不同的函数中获取同一个锁。但请留神,尽管递归锁能够使得代码更加灵便,然而它也使得代码更难了解,更难保障线程同步的正确性,因而应尽量避免应用递归锁,除非的确有须要。
四、条件变量(Condition)
条件变量(Condition)是另一种罕用的线程同步机制,它容许一个或多个线程期待某个条件成立,而后才继续执行。条件变量通常与一个关联的锁一起应用,这个锁能够被多个线程共享。
以下是一个应用条件变量的例子:
import threading# 创立一个条件变量condition = threading.Condition()def worker1(): with condition: # 期待条件成立 condition.wait() # 访问共享数据 print("Worker 1 is working...")def worker2(): with condition: # 访问共享数据 print("Worker 2 is working...") # 告诉其余线程条件曾经成立 condition.notify()# 创立两个线程thread1 = threading.Thread(target=worker1)thread2 = threading.Thread(target=worker2)# 启动线程thread1.start()thread2.start()# 期待所有线程完结thread1.join()thread2.join()
在这个例子中,线程1必须期待线程2告诉条件成立后,能力继续执行。
五、信号量(Semaphore)
信号量(Semaphore)是一个更高级的线程同步机制,它保护了一个外部计数器,该计数器被acquire()
调用减一,被release()
调用加一。当计数器大于零时,acquire()
不会阻塞。当线程调用acquire()
并导致计数器为零时,线程将阻塞,直到其余线程调用release()
。
以下是一个应用信号量的例子:
import threading# 创立一个信号量semaphore = threading.Semaphore(2)def worker(): # 获取信号量 semaphore.acquire() try: # 访问共享数据 print("Thread is working...") finally: # 开释信号量 semaphore.release()# 创立三个线程thread1 = threading.Thread(target=worker)thread2 = threading.Thread(target=worker)thread3 = threading.Thread(target=worker)# 启动线程thread1.start()thread2.start()thread3.start()# 期待所有线程完结thread1.join()thread2.join()thread3.join()
在这个例子中,咱们创立了一个值为2的信号量,这意味着最多只有两个线程能够同时访问共享数据。
以上就是Python中线程同步的几种次要办法,应用适当的线程同步机制能够确保你的多线程程序正确、平安地执行。