python 高并发开发中, 有时候主程序需要获取线程的执行结果, 然后再继续做些处理, 下面介绍几种方法:
1 利用 ThreadPoolExecutor 任务提交后的返回值对象 Future
直接上例子:
from concurrent.futures import ThreadPoolExecutor
import time
def task(n):
time.sleep(n) # 让任务暂停n秒, 模拟一个耗时的任务
return n
executor = ThreadPoolExecutor(max_workers=1) # 创建一个线程池,最大工作线程数为1
future = executor.submit(task, 2) # 提交任务到线程池,参数是2, 返回一个 Future 对象
# 死循环, 监控future 的结果
while True:
if future.done(): # 如果任务完成
print("任务已完成")
break
elif future.running(): # 如果任务正在运行
print("任务仍在运行")
elif future.cancelled(): # 如果任务被取消
print("任务已被取消")
time.sleep(0.5) # 每0.5秒检查一次任务状态
# 获取线程的执行结果
if future.done() and not future.cancelled(): # 如果任务完成且未被取消
print("结果:", future.result()) # 打印任务结果
上述例子向ThreadPoolExecutor提交任务后, 拿到一个Future对象, 然后不停地检测 Future 对象的状态, 当状态是done的时候, 打印输出结果。
2 自定义Thread 利用 Future 对象
from concurrent.futures import Future
import threading
import time
def do_task(number, future):
time.sleep(number) # 根据输入的数字睡眠相应的秒数
future.set_result(number ** 2 ) # 将该数字的平方设置为任务的结果
def do_task_async(number):
future = Future() # 创建一个 Future 对象
t = threading.Thread(target=do_task, args=(number, future)) # 创建一个线程,目标函数是 do_task
t.start() # 启动线程
return future # 返回 Future 对象
future = do_task_async(5) # 异步执行任务
# 死循环, 监控future 的结果
while True:
if future.done(): # 如果任务完成
print("任务已完成")
break
elif future.running(): # 如果任务正在运行
print("任务仍在运行")
elif future.cancelled(): # 如果任务被取消
print("任务已被取消")
else:
print("任务仍在pending") # 如果任务既没有完成,也没有在运行,也没有被取消,那么任务就是 pending 状态
time.sleep(0.5) # 每0.5秒检查一次任务状态
# 获取线程的执行结果
if future.done() and not future.cancelled(): # 如果任务完成且未被取消
print("结果:", future.result()) # 打印任务结果
这个例子中我们自己定义的 Future对象从定义完成后, 一致是 pending 状态, 当被设置 set_result 后, 状态变为done. 这状态的变化和第一个例子是不一样的, ThreadPoolExecutor 提交任务后的future, 状态是running, 正常运行完成后才会变为 done.
实际上 也可以对 Future 设置回调函数, 设置当结束后, 执行某些操作, 感兴趣的可以查看如何设置回调函数: add_done_callback。
3 利用queue.Queue()
queue.Queue() 是 Python 标准库中 queue 模块的一个类,它提供了线程安全的队列实现。 queue.Queue() 创建一个先进先出(FIFO)的队列,可以在多个线程之间安全的共享和操作。它提供了一些主要的方法,包括:
put(item): 将一个元素添加到队列的末尾。
get(): 从队列的头部移除并返回一个元素。如果队列为空,这个方法会阻塞,直到有元素可用。
empty(): 如果队列为空,返回 True,否则返回 False。
full(): 如果队列已满,返回 True,否则返回 False。
qsize(): 返回队列中的元素数量。
直接看一个例子:
import threading
import queue
import time
def worker(num, output_queue):
"""线程工作函数。它会根据输入的数字睡眠相应的秒数,然后将该数字的平方放入输出队列。"""
print('Worker:', num)
time.sleep(num) # 模拟耗时任务
output_queue.put(num ** 2) # 将该数字的平方放入输出队列
# 创建一个队列来保存结果
q = queue.Queue()
# 创建一个列表来保存工作线程
threads = []
# 创建并启动工作线程
for i in range(5):
t = threading.Thread(target=worker, args=(i, q)) # 创建一个工作线程
threads.append(t) # 将工作线程添加到列表中
t.start() # 启动工作线程
# 等待所有工作线程完成
for t in threads:
t.join()
# 从队列中获取并打印结果
while not q.empty():
print(q.get()) # 打印结果
print("all done") # 表示所有工作线程已完成
例子中先定义可一个queue.Queue(), 然后作为参数传递到每一个线程中, 线程中的结果存储到queue中, 待线程结束后, 从q中获取线程的结果。