多线程编程是Python应用中的一个重要部分,正确处理线程间的共享和释放问题是保证程序正确性的重要一环。本文将从以下方面介绍Python下线程之间的共享和释放:
1. 共享变量:介绍了多个线程同时访问共享变量的情况以及可能产生的问题,同时提供了线程安全的解决方式;
2. 信号量:介绍了使用信号量完成线程之间的同步,保证临界资源的正确性;
3. 互斥锁:介绍了线程之间使用互斥锁来保护共享资源,防止并发产生问题;
4. 条件变量:介绍了在复杂的多线程操作中,使用条件变量来保证同步。
Python线程共享变量
多线程中最常见的问题就是线程之间的数据共享和访问问题。由于线程之间可能随时切换,如果多个线程同时访问同一个共享变量,可能会导致竞态条件(Race Condition)的问题,产生数据的不一致或者错误。
Python提供了一个线程锁(thread.Lock)来保护共享资源:
import threading
def worker(lock, data):
with lock:
print(threading.current_thread().name, 'begin to work')
data[0] += 1
print(threading.current_thread().name, 'work finished', data[0])
if __name__ == '__main__':
lock = threading.Lock()
data = [0]
th1 = threading.Thread(target=worker, args=(lock, data), name='th1')
th2 = threading.Thread(target=worker, args=(lock, data), name='th2')
th1.start()
th2.start()
上面的代码就是使用thread.Lock同步两个线程修改共享变量的值。
信号量
Python中的信号量(Semaphore)是一个计数器。对于获取该信号量的线程,信号量计数器就减1;对于释放该信号量的线程,计数器就加1。当计数器为0时,获取该信号量的线程就会被挂起,直到其他线程释放该信号量。
以下代码用Semaphore同步三个线程:
import time
import threading
def worker(sem, data):
with sem:
print(threading.current_thread().name, 'begin to work')
data[0] += 1
print(threading.current_thread().name, 'work finished', data[0])
if __name__ == '__main__':
sem = threading.Semaphore(2)
data = [0]
threads = []
for i in range(3):
th = threading.Thread(target=worker, args=(sem, data), name='th%s' % (i+1))
th.start()
threads.append(th)
for th in threads:
th.join()
互斥锁
Python中的互斥锁(Lock)是用于保护多个线程访问共享资源的工具,以防止两个线程同时读写同一块内存区域的问题。
以下代码用Lock同步两个线程:
import time
import threading
def worker(lock, data):
with lock:
print(threading.current_thread().name, 'begin to work')
data[0] += 1
print(threading.current_thread().name, 'work finished', data[0])
if __name__ == '__main__':
lock = threading.Lock()
data = [0]
th1 = threading.Thread(target=worker, args=(lock, data), name='th1')
th2 = threading.Thread(target=worker, args=(lock, data), name='th2')
th1.start()
th2.start()
条件变量
Python中的条件变量(Condition)是一种高级锁,它允许一个或多个线程等待某个东西发生(或者某个条件变为真),然后继续执行。在某个东西发生或者条件变为真之前,所有调用wait()和wait_for()的线程都会被挂起。
以下代码用条件变量同步两个线程:
import time
import threading
def producer(cv, data):
for i in range(5):
with cv:
data.append(i)
cv.notify_all()
cv.wait()
def consumer(cv, data):
for i in range(5):
with cv:
while not data:
cv.wait()
print(data.pop(0))
cv.notify_all()
if __name__ == '__main__':
cv = threading.Condition()
data = []
th1 = threading.Thread(target=producer, args=(cv, data), name='producer')
th2 = threading.Thread(target=consumer, args=(cv, data), name='consumer')
th1.start()
th2.start()
th1.join()
th2.join()