[Python]线程池与进程池简介

在《多进程并发与同步》和《多线程与同步简介》中介绍了线程与进程;但因启动进程与线程都需要代价,在频繁使用时,就需要通过线程池与进程池实现。

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的不同:

PoolProcessPoolExecutor
不能取消任务可以取消任务
不能在不同任务上wait可wait任务集合
能停止池中所有任务不能停止池中所有任务
有多个版本map操作不能map
不能access异常可access异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值