文章目录
在《多进程并发与同步》和《多线程与同步简介》中介绍了线程与进程;但因启动进程与线程都需要代价,在频繁使用时,就需要通过线程池与进程池实现。
concurrent.futures模块
标准库concurrent.futures
模块,提供了ProcessPoolExecutor(进程池,对multiprocessing的封装抽象)和ThreadPoolExecutor(线程池,对threading的封装和抽象)两个类,不仅可自动调度线程,还可以做到(以线程池为例说明):
- 主线程可以获取某一个线程(或者任务)的状态,以及返回值;
- 当一个线程完成的时候,主线程能够立即知晓;
- 让多线程和多进程的编码接口一致;
ThreadPoolExecutor
最简单使用线程池的方式,就是通过submit提交任务然后等待执行完成后获取结果:
- max_workers参数来设置线程中最多能同时运行的线程数;
- submit函数(非阻塞,立即返回)提交线程需要执行任务到线程池中,并返回future;
- 通过future可判断任务是否完成(
done()
方法),以及获取返回值(result()
方法)。
def spider(url):
# ...
return page
# urls = [www.baidu.com, www.126.com]
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
tasks = [executor.submit(spider, u) for u in urls]
concurrent.futures.wait(tasks)
for t in tasks:
for r in t.result():
results.append(r)
as_completed
通过as_completed(futures, timeout=None)
可返回已完成任务的迭代器:
- 最先执行完成的,先返回;
- 若有重复任务,只是返回一次。
# 如上,不要wait,可直接获取完成的迭代器(效率更高)
for t in as_completed(tasks):
print("result:", t.result())
wait
通过wait(futures, timeout=None, return_when=ALL_COMPLETED)
可等待任务完成:
- 返回为两个集合类型的元素,第一个集合装着已经完成的future,第二个集合装着未完成的future。
- return_when决定了什么时候返回:
- FIRST_COMPLETED:有任何一个任务完成(或被取消)时;
- FIRST_EXCEPTION:有任何一个任务抛出异常时(或所有任务都成功执行完成)时;
- ALL_COMPLETED:所有任务的执行完成(或被取消)时;
map
通过map(func, *iterables, timeout=None)
可一次提交多个任务:
results = executor.map(spider, urls)
for r in results:
print("result:", r) # map返回的就是原始结果
multiprocessing模块
multiprocessing模块中提供了pool.Pool
(进程池)和pool.ThreadPool
(线程池)两个类。
Pool
Pool可通过initializer参数来设定线程初始化函数,做初始化工作:
def procSpider(url):
evtStart.wait()
# ...
return page
def procInit(evt):
baseLog.init_logging(logLevel=logging.INFO) # 设定进程的日志级别(需要每个进程都要设定)
global evtStart
evtStart = evt
# 通过evtStart来通知一起开始执行
def processBatch(processes, workers):
global evtStart
# urls = [www.baidu.com, www.126.com]
evtStart = multiprocessing.Event()
with multiprocessing.Pool(processes=processes, initializer=procInit, initargs=(evtStart,)) as pool:
futures = [pool.apply_async(procSpider, u) for u in urls]
time.sleep(1)
evtStart.set()
for fu in futures:
result = fu.get()
print("result:", result)
apply
apply(func[, args[, kwds]])
是同步方式提交,只有执行完成后才会返回结果。
apply_async(func[, args[, kwds[, callback[, error_callback]]]])
是异步方式提交,返回一个 AsyncResult对象:
- callback是一个接受单个参数的可调用对象;当任务执行成功时,其结果作为callback参数返回;
- error_callback须是一个接受单个参数的可调用对象;当任务执行失败时,以异常为参数调用此函数;
map
map(func, iterable[, chunksize])
与map_async(func, iterable[, chunksize[, callback[, error_callback]]])
与apply类似,但是一次可提交多个任务。
AsyncResult
AsyncResult为异步提交时返回的对象:
get([timeout])
:获取执行结果;wait([timeout])
:等待完成;ready()
:返回是否已完成状态;successful()
:判断是否完成,且成功;
Pool与ProcessPoolExecutor
Pool与ProcessPoolExecutor的不同:
Pool | ProcessPoolExecutor |
---|---|
不能取消任务 | 可以取消任务 |
不能在不同任务上wait | 可wait任务集合 |
能停止池中所有任务 | 不能停止池中所有任务 |
有多个版本map操作 | 不能map |
不能access异常 | 可access异常 |