python线程池理解
在编码需要多线程的时候,我们并不希望多个线程一次性全都开始,而是我们能控制线程的数量,能在主线程中获取某一个线程的状态或者某一个任务的状态和他的返回值,还能在某一个线程完成时可以在主线程得到消息。这个时候来介绍下futures包。
future包有个优点,它可以让多线程和多进程编码接口一致。它还有个ThreadPoolExecutor类,一个线程池管理包工具类。
我们写一个do_work函数,顺带认识下ThreadPoolExecutor的各种方法
"""
@File : futures_use.py
@Author: Gareth
@Date : 2019/10/10 20:04
@Desc :
"""
from concurrent.futures import ThreadPoolExecutor
import time
def do_work(times):
time.sleep(times)
print("do work %d success" % times)
return "work %d" % times
executor = ThreadPoolExecutor(max_workers=2)
work1 = executor.submit(do_work, (3)) # submit函数可以提交执行的函数到线程池中
work2 = executor.submit(do_work, (1)) # 注意这里函数内传的第一个参数是传入要执行的函数名,不带括号
# submit 执行后立即返回,不等待(非阻塞)
print(work1.done()) # done方法返回的是这个执行的函数执行得是否成功
time.sleep(4) # 因为submit非阻塞,所以第一回done返回的是False,如果睡4秒,结果就是True了
print(work1.done())
print(work1.result()) # 获取work1的执行结果
# work1.cancel() 取消任务,如果任务执行中是无法取消的。
运行结果
# False
# do work 1 success
# do work 3 success
# True
# work 3
当然这些都是介绍简单的函数应用,如果我们想要获取已经成功的task的返回
这里任务的提交我们不再一个个提交,我们建立一个任务的列表work_list
from concurrent.futures import ThreadPoolExecutor, as_completed # 注意这里又导入了新包(本质生成器)
import time
def do_work(times):
time.sleep(times)
print("do work %d success" % times)
return "work %d" % times
# TODO 这里submit里传入的函数参数是以什么形式传入,按照下面这样传的话是集合,
# 但大多数见到的都是以元组形式,我改成元组形式如(3,),结果就不对,希望下回能有解决
executor = ThreadPoolExecutor(max_workers=2)
# work1 = executor.submit(do_work, (3)) # submit函数可以提交执行的函数到线程池中
# work2 = executor.submit(do_work, (1)) # 注意这里函数内传的第一个参数是传入要执行的函数名,不带括号
# # submit 执行后立即返回,不等待(非阻塞)
# print(work1.done()) # done方法返回的是这个执行的函数执行得是否成功
# time.sleep(4) # 因为submit非阻塞,所以第一回done返回的是False,如果睡4秒,结果就是True了
# print(work1.done())
# print(work1.result()) # 获取work1的执行结果
# work1.cancel() 取消任务,如果任务执行中是无法取消的。
work_list = [4, 2, 5] # 睡4, 2, 5秒
all_task = [executor.submit(do_work, (work)) for work in work_list]
for future in as_completed(all_task):
data = future.result()
print("%s success" % data)
# 执行结果
# do work 2 success
# work 2 success
# do work 4 success
# work 4 success
# do work 5 success
# work 5 success
最后再介绍一下wait()函数,同样有着阻塞的作用,作用是等待指定某一个任务或者是一些任务完成后,才继续往下执行
from concurrent.futures import ThreadPoolExecutor, wait
import time
def do_work(times):
time.sleep(times)
print("do work %d success" % times)
return "work %d" % times
executor = ThreadPoolExecutor(max_workers=2)
work_list = [4, 2, 5] # 睡4, 2, 5秒
all_task = [executor.submit(do_work, (work)) for work in work_list]
wait(all_task) # 等待
print("main thread")
# 执行结果
# do work 2 success
# do work 4 success
# do work 5 success
# main thread
wait函数还有别的参数可以传,我们进源码看
def wait(fs, timeout=None, return_when=ALL_COMPLETED):
他还有个return_when的参数,默认是"ALL_COMPLETED",所有都完成。
还有别的参数
FIRST_COMPLETED = 'FIRST_COMPLETED'
FIRST_EXCEPTION = 'FIRST_EXCEPTION'
ALL_COMPLETED = 'ALL_COMPLETED'
_AS_COMPLETED = '_AS_COMPLETED'
当然看名字就知道什么意思,这里就不多赘述,我们换一个参数,试下“FIRST_COMPLETED”
from concurrent.futures import ThreadPoolExecutor, wait, FIRST_COMPLETED
import time
def do_work(times):
time.sleep(times)
print("do work %d success" % times)
return "work %d" % times
executor = ThreadPoolExecutor(max_workers=2)
work_list = [4, 2, 5] # 睡4, 2, 5秒
all_task = [executor.submit(do_work, (work)) for work in work_list]
wait(all_task, return_when=FIRST_COMPLETED) # 等待
print("main thread")
# 执行结果
# do work 2 success
# main thread
# do work 4 success
# do work 5 success
结果是第一个任务结束就打印了main thread
+++++
有一个点没弄懂,submit里的函数参数必须传入集合(把参数放入集合里),但大多数情况看到的都是传入一个元组,把参数放入元组里。