Python–cookbook–12.并发编程
相关介绍
# coding=utf8
import time
from threading import Thread, Event, Condition, Semaphore
import multiprocessing
from queue import Queue
import heapq
# 并发执行的代码创建/销毁线程
def countdown(n):
while n > 0:
print('T-minus', n)
n -= 1
time.sleep(5)
# t = Thread(target=countdown, args=(3,))
# 对于需要长时间运行的线程或者需要一直运行的后台任务,你应当考虑使用后台线程
# t = Thread(target=countdown, args=(3,), daemon=True) # 后台线程
# t.start() # 开始执行
# if t.is_alive():
# print('Still running')
# else:
# print('Completed')
# 无法结束一个线程,无法给它发送信号,无法调整它的调度,也无法执行其他高级操作
# 你需要终止线程,那么这个线程必须通过编程在某个特定点轮询来退出
class CountdownTask:
def __init__(self):
self._running = True
def terminate(self):
self._running = False
def run(self, n):
while self._running and n > 0:
print('T-minus', n)
n -= 1
time.sleep(5)
# c = CountdownTask()
# t = Thread(target=c.run, args=(3,))
# t.start()
# c.terminate() # Signal termination
# t.join() # Wait for actual termination (if needed)
# 由于全局解释锁(GIL)的原因,Python 的线程被限制到同一时刻只允许一个线
# 程执行这样一个执行模型。所以,Python 的线程更适用于处理 I/O 和其他需要并发执
# 行的阻塞操作(比如等待 I/O、等待从数据库获取数据等等),而不是需要多处理器并
# 行的计算密集型任务。
# event.isSet():返回event的状态值;
# event.wait():如果 event.isSet()==False将阻塞线程;
# event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
# event.clear():恢复event的状态值为False。
# 判断线程是否已经启动
def countdown2(n, started_evt):
print('countdown starting')
started_evt.set()
while n > 0:
print('T-minus', n)
n -= 1
time.sleep(2)
# started_evt = Event()
# print('Launching countdown')
# t = Thread(target=countdown2, args=(5, started_evt))
# t.start()
# started_evt.wait()
# print('countdown is running')
# # “countdown is running”总是显示在“countdown starting”之后显示
# 如果一个线程需要不停地重复使用 event 对象,你最好使用 Condition 对象来代替
# wait :等待条件通知
# wait_for:等待某个条件的通知
# notify :唤醒一个或多个正在等待的condtion
# notify_all:唤醒所有正在等待的condtion
class PeriodicTimer:
def __init__(self, interval):
self._interval = interval
self._flag = 0
self._cv = Condition()
def start(self):
t = Thread(target=self.run)
t.daemon = True
t.start()
def run(self):
while True:
time.sleep(self._interval)
with self._cv:
self._flag ^= 1
self._cv.notify_all()
def wait_for_tick(self):
with self._cv:
last_flag = self._flag
while last_flag == self._flag:
self._cv.wait()
ptimer = PeriodicTimer(1)
ptimer.start()
def countdown3(nticks):
while nticks > 0:
ptimer.wait_for_tick()
print('countdown3', nticks)
nticks -= 1
def countup(last):
n = 0
while n < last:
ptimer.wait_for_tick()
print('countup', n)
n += 1
Thread(target=countdown3, args=(10,)).start()
Thread(target=countup, args=(5,)).start()
# 使用信号量实现
# def worker(n, sema):
# sema.acquire()
# print('Working', n)
# sema = Semaphore(0)
# nworkers = 10
# for n in range(nworkers):
# t = Thread(target=worker, args=(n, sema,))
# t.start()
# sema.release()
# 线程间通信
_sentinel = object() # 用来关闭,终止执行
def producer(out_q):
while True:
# ... 产生数据
data = 1
out_q.put(data)
break
out_q.put(_sentinel)
def consumer(in_q):
while True:
data = in_q.get()
# 运行数据 ...
if data is _sentinel:
in_q.put(_sentinel)
break
# # Create the shared queue and launch both threads
# q = Queue()
# t1 = Thread(target=consumer, args=(q,))
# t2 = Thread(target=producer, args=(q,))
# t1.start()
# t2.start()
# 线程安全的优先级队列
class PriorityQueue:
def __init__(self):
self._queue = []
self._count = 0
self._cv = Condition()
def put(self, item, priority):
with self._cv:
heapq.heappush(self._queue, (-priority, self._count, item))
self._count += 1
self._cv.notify()
def get(self):
with self._cv:
while len(self._queue) == 0:
self._cv.wait()
return heapq.heappop(self._queue)[-1]
# 给关键部分加锁