当我们使用python中的多线程编程时,有一些共享的资源需要被不同的线程访问和修改,但是同时又需要保证同一时间只有一个线程能够访问和修改这些共享资源,否则就会出现数据不一致的情况。这时候就需要使用同步机制,而pythond的高级锁Condition
就能够很好地完成这项工作。
下面我们来详细介绍一下Condition
的使用方法,分别有以下几个方面:
- Condition的初始化
- Condition的wait方法
- Condition的notify方法
- Condition的notify_all方法
1. Condition的初始化
在使用Condition
时,我们首先需要通过threadin.locks
模块中的RLock
类创建一个可重入锁,然后再使用这个锁初始化一个Condition
对象。下面我们通过代码来演示这个过程:
import threading
# 创建可重入锁
lock = threading.RLock()
# 通过可重入锁初始化Condition对象
condition = threading.Condition(lock)
2. Condition的wait方法
Condition
中有一个wait()
方法,当线程访问到某个共享资源时,如果该资源不可用,则调用wait()
方法自动阻塞线程,直到该资源可用时再被唤醒。同时,在调用wait()
方法之前需要获取关联的锁,否则会抛出RuntimeError
异常。
下面我们来看一个简单的示例,假设有两个线程分别需要同时访问一个共享资源resource
,并且如果resource
已经被其中一个线程占用,则另一个线程需要等待,等到resource
被释放后才能够继续访问。这个过程可以通过下面的代码来实现:
import threading
import time
# 创建可重入锁
lock = threading.RLock()
# 通过可重入锁初始化Condition对象
condition = threading.Condition(lock)
# 共享资源
resource = 0
# 线程1
def thread1():
global resource
with lock:
# 如果resource已经被占用则等待
while resource != 0:
condition.wait()
# 将resource占用
resource = 1
print("Thread 1: get resource")
time.sleep(2)
# 释放resource
resource = 0
print("Thread 1: release resource")
condition.notify()
# 线程2
def thread2():
global resource
with lock:
# 如果resource已经被占用则等待
while resource != 0:
condition.wait()
# 将resource占用
resource = 2
print("Thread 2: get resource")
time.sleep(2)
# 释放resource
resource = 0
print("Thread 2: release resource")
condition.notify()
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)
t1.start()
t2.start()
上面的代码中,线程1和线程2分别使用了wait()
方法等待resource
变为可用,并且在获取到resource
后进行了一段耗时的操作,最后释放该资源,同时通过调用notify()
方法唤醒其它等待该资源的线程。
3. Condition的notify方法
当某个线程完成共享资源的修改后,需要唤醒等待该资源的线程,这时候就可以调用notify()
方法解除一个等待该资源的线程的阻塞,使其可以继续执行。需要注意的是,如果当前有多个线程等待该资源,那么调用notify()
方法只会解除其中的一个线程的阻塞,如果要唤醒全部等待该资源的线程,可以使用notify_all()
方法。
下面我们再来看一个示例,假设有多个线程需要同时访问一个限流器,但是限流器同一时间只允许一个线程进行访问,如果超过限制则需要等待,这个过程可以通过下面的代码来实现:
import threading
# 创建可重入锁
lock = threading.RLock()
# 通过可重入锁初始化Condition对象
condition = threading.Condition(lock)
# 限流器,一次只允许一个线程访问
rate_limiter = threading.Semaphore(1)
# 线程
def worker(worker_id):
# 访问限流器
rate_limiter.acquire()
print("Thread {} get rate limiter".format(worker_id))
# 释放限流器
rate_limiter.release()
with lock:
# 通知其它等待该资源的线程可以开始执行
condition.notify()
print("Thread {} start working".format(worker_id))
# 模拟耗时的操作
time.sleep(1)
print("Thread {} finish working".format(worker_id))
threads = []
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
for t in threads:
t.start()
在上面的代码中,通过Semaphore
限制了同时访问限流器的线程数为1,当一个线程成功获取限流器后才能够对共享资源进行访问,如果有其它线程需要访问,那么就需要在wait()
方法等待,当当前线程完成对共享资源的访问后,释放限流器并且通过notify()
方法通知其它等待该资源的线程可以开始执行。
4. Condition的notify_all方法
notify_all()
方法和notify()
方法类似,不同的是它能够唤醒所有等待该资源的线程。下面我们通过简单的示例来演示这个过程,假设有多个线程需要同时访问一个"桥",但是桥只能容纳一辆车通过,如果当前桥上有车,则其它车辆需要等待,这个过程可以通过下面的代码来实现:
import threading
# 创建可重入锁
lock = threading.RLock()
# 通过可重入锁初始化Condition对象
condition = threading.Condition(lock)
# 资源
bridge = 0
# 线程
def worker(worker_id):
global bridge
with lock:
# 如果当前桥有车,则需要等待
while bridge != 0:
condition.wait()
# 过桥
bridge = 1
print("Car {} passed the bridge".format(worker_id))
# 离开桥
bridge = 0
# 唤醒其它车辆继续过桥
condition.notify_all()
threads = []
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
for t in threads:
t.start()
在上面的代码中,如果当前桥上有车,则需要等待,当桥被当前车辆通过后离开,并且唤醒其它等待该资源的车辆通过。这个过程可以通过notify_all()
方法实现。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python多线程高级锁condition简单用法示例 - Python技术站