一、Semaphore(信号量)
Semaphore(信号量)是一种同步机制,用于控制多个线程对共享资源的访问。Semaphore可以控制同时访问共享资源的线程数量,从而避免资源竞争和死锁。
Semaphore有两个主要的操作:acquire(获取)和release(释放)。当一个线程需要访问共享资源时,它会调用Semaphore的acquire方法来获取一个信号量。如果此时Semaphore的计数器为0,则线程会被阻塞,直到有一个信号量可用。当线程完成对共享资源的访问后,它会调用Semaphore的release方法来释放一个信号量,使得其他线程可以继续访问共享资源。
下面是一个简单的Semaphore使用示例:
import threading
# 创建一个Semaphore对象,初始计数器为3
semaphore = threading.Semaphore(3)
def worker():
# 获取一个信号量
semaphore.acquire()
print('Thread {} is working'.format(threading.current_thread().name))
# 模拟工作时间
for i in range(5):
print('Thread {} is working ({}/5)'.format(threading.current_thread().name, i+1))
# 释放一个信号量
semaphore.release()
# 创建5个线程
threads = []
for i in range(5):
t = threading.Thread(target=worker, name='Thread-{}'.format(i+1))
threads.append(t)
# 启动线程
for t in threads:
t.start()
# 等待所有线程完成
for t in threads:
t.join()
在上面的示例中,我们创建了一个Semaphore对象,并将初始计数器设置为3。然后创建了5个线程,每个线程都会调用worker函数来模拟对共享资源的访问。在worker函数中,我们首先调用Semaphore的acquire方法来获取一个信号量,然后进行模拟工作,最后调用Semaphore的release方法来释放一个信号量。由于Semaphore的初始计数器为3,因此最多只有3个线程可以同时访问共享资源,其他线程会被阻塞,直到有一个信号量可用。
二、Lock(锁)
Lock(锁)是一种同步机制,用于控制多个线程对共享资源的访问。Lock可以确保在任何时刻只有一个线程可以访问共享资源,从而避免资源竞争和死锁。
在Python中,Lock可以使用threading模块中的Lock类来实现。Lock类有两个主要的操作:acquire(获取)和release(释放)。当一个线程需要访问共享资源时,它会调用Lock的acquire方法来获取锁。如果此时锁已经被其他线程占用,则线程会被阻塞,直到锁被释放。当线程完成对共享资源的访问后,它会调用Lock的release方法来释放锁,使得其他线程可以继续访问共享资源。
下面是一个简单的Lock使用示例:
import threading
# 创建一个Lock对象
lock = threading.Lock()
# 共享变量
count = 0
def worker():
global count
# 获取锁
lock.acquire()
print('Thread {} is working'.format(threading.current_thread().name))
# 修改共享变量
for i in range(100000):
count += 1
# 释放锁
lock.release()
# 创建5个线程
threads = []
for i in range(5):
t = threading.Thread(target=worker, name='Thread-{}'.format(i+1))
threads.append(t)
# 启动线程
for t in threads:
t.start()
# 等待所有线程完成
for t in threads:
t.join()
# 输出共享变量的值
print('count =', count)
在上面的示例中,我们创建了一个Lock对象,并将其赋值给变量lock。然后创建了5个线程,每个线程都会调用worker函数来修改共享变量count。在worker函数中,我们首先调用Lock的acquire方法来获取锁,然后进行修改共享变量的操作,最后调用Lock的release方法来释放锁。由于Lock只允许一个线程访问共享资源,因此对共享变量的修改是安全的。
需要注意的是,在使用Lock时,一定要确保在修改共享资源之前获取锁,在修改完成之后释放锁,否则可能会导致死锁或者资源竞争的问题。
三、Semaphore跟Lock有什么区别
Semaphore和Lock都是用于控制多个线程对共享资源的访问的同步机制,但它们有一些区别。
1.控制访问数量:Semaphore可以控制同时访问共享资源的线程数量,而Lock只能控制同时只有一个线程访问共享资源。
2.计数器:Semaphore有一个计数器,每次acquire操作会将计数器减1,每次release操作会将计数器加1。而Lock没有计数器,只有一个锁状态。
3.等待机制:当一个线程调用Semaphore的acquire方法时,如果计数器为0,则线程会被阻塞,直到有一个信号量可用。而当一个线程调用Lock的acquire方法时,如果锁已经被其他线程占用,则线程会被阻塞,直到锁被释放。
4.用途:Semaphore适用于控制对一组资源的访问,例如线程池、数据库连接池等。而Lock适用于控制对单个资源的访问,例如共享变量、文件等。
总的来说,Semaphore比Lock更加灵活,可以控制多个线程同时访问共享资源的数量,而Lock只能控制一个线程访问共享资源。但在某些情况下,Lock可能更加简单和高效。