Python标准库14:多线程并发编程
- 编程知识
- 2023-06-21
- 3
本文将从多个方面对Python标准库14进行详细阐述,包括多线程编程、锁、信号量、队列等相关知识。
一、多线程编程
多线程是指在同一进程中同时运行多个线程,每个线程都有自己的执行序列。Python标准库中的threading
模块提供多线程编程的相关支持。
我们可以通过创建Thread
对象并调用其start()
方法来创建并启动一个新线程。下面是一个简单的例子:
import threading def print_numbers(): for i in range(5): print(i) t = threading.Thread(target=print_numbers) t.start()
在上面的例子中,我们定义了一个print_numbers()
函数用于打印0到4的数字,并创建了一个Thread
对象t
。调用t.start()
方法启动新线程。
二、锁
在多线程编程中,可能会存在多个线程同时访问同一个资源的情况。这时就需要用到锁来保证资源的安全访问。Python标准库中的threading.Lock
类提供了锁的相关支持。
我们可以使用Lock
类来创建锁,并使用acquire()
方法和release()
方法来获取和释放锁。下面是一个简单的例子:
import threading class Counter: def __init__(self): self.lock = threading.Lock() self.count = 0 def increment(self): with self.lock: self.count += 1 counter = Counter() def worker(): for i in range(10000): counter.increment() t1 = threading.Thread(target=worker) t2 = threading.Thread(target=worker) t1.start() t2.start() t1.join() t2.join() print(counter.count)
在上面的例子中,我们创建了一个Counter
类,其中包含一个Lock
对象lock
和一个计数器count
。在increment()
方法中,我们使用with
语句获取锁并对计数器进行增加操作。
我们创建了两个线程来进行计数,在每个线程中循环10000次,并调用increment()
方法进行计数。通过t1.join()
和t2.join()
方法,我们确保在输出计数器的值之前,两个线程都已经执行完毕。
三、信号量
信号量是一种类似于锁的机制,可以用于控制并发访问的数量。Python标准库中的threading.Semaphore
类提供了信号量的相关支持。
我们可以使用Semaphore
类来创建信号量,并使用acquire()
方法和release()
方法来获取和释放信号量。下面是一个简单的例子:
import threading semaphore = threading.Semaphore(2) def worker(): with semaphore: print('Thread %s is working.' % threading.current_thread().name) t1 = threading.Thread(target=worker, name='A') t2 = threading.Thread(target=worker, name='B') t3 = threading.Thread(target=worker, name='C') t1.start() t2.start() t3.start()
在上面的例子中,我们创建了一个信号量对象semaphore
,设置初始值为2。然后我们创建了三个线程t1
、t2
和t3
。在每个线程中,我们使用with
语句获取信号量并输出当前线程的名字。
由于semaphore
的初始值为2,因此前两个线程可以同时运行,而第三个线程需要等待前两个线程中的任意一个释放信号量后才能开始运行。
四、队列
队列是一种常见的数据结构,可以用于多线程编程中的任务分发和结果收集等场景。Python标准库中的queue
模块提供了队列的相关支持。
我们可以使用queue.Queue
类创建一个队列,并使用put()
方法和get()
方法往队列中添加元素和取出元素。下面是一个简单的例子:
import queue import threading q = queue.Queue() def worker(): while True: item = q.get() if item is None: break print(item) t1 = threading.Thread(target=worker) t2 = threading.Thread(target=worker) t1.start() t2.start() for i in range(10): q.put(i) q.put(None) q.put(None) t1.join() t2.join()
在上面的例子中,我们创建了一个队列q
,并创建了两个线程t1
和t2>来处理队列中的数据。在每个线程中,我们使用一个无限循环来取出队列中的元素,直到取出的元素是
None
。
在主线程中,我们往队列中添加了10个元素,然后分别往队列中添加了两个None
元素,用于结束线程。最后我们通过t1.join()
和t2.join()
方法,确保两个线程都已经执行完毕。