Python 现代开发学习笔记

(二)线程的启动、等待与结果传递

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 接收每个任务的值或错误。

笔记正文与全部题解 · Ctrl / ⌘ K