(二)线程的启动、等待与结果传递
1. 先启动所有线程,再等待结束
一个进程中可以有多个线程,它们使用同一个进程中的对象。Thread 接收要调用的函数,start() 才启动新线程;直接调用 run() 仍是在当前线程执行。
# 项目文件:demos/thread_start.py
# 工作线程把结果放进 Queue,主线程等全部结束后按编号恢复输入顺序。
from queue import Queue
from threading import Thread
from time import sleep
def worker(index, title, delay, results):
sleep(delay)
results.put((index, title))
if __name__ == "__main__":
results = Queue()
items = [("Python", 0.06), ("NumPy", 0.02), ("Pygame", 0.04)]
threads = [
Thread(target=worker, args=(i, title, delay, results))
for i, (title, delay) in enumerate(items)
]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
completed = [results.get() for _ in items]
print([title for index, title in sorted(completed)])输出仍是原来的书目顺序。线程可能按另一个次序完成,主线程不靠完成先后猜书籍编号。join() 让当前线程等待指定线程结束;如果在每次 start() 后立刻 join(),这一轮就等完才开始下一轮,等待又被串起来了。
queue.Queue 提供适合线程之间传递对象的 put、get 操作。上面先 join,知道三个工作线程都已放入结果,再读取三项。第六章的日志可以保留线程名 %(threadName)s,便于追踪操作来自哪里。Thread 与同步工具
2. 返回值与错误需要有人接收
线程目标函数的返回值不会由 join() 交回来;工作线程中未处理的异常也不会让主线程的 join() 抛出同一个异常。任务较多时,可以让线程池统一管理工作线程,再用 Future 接收每个任务的值或错误。