Python 进程池与线程池

python提供了一个新的标准或者说内置的模块,这个模块里面提供了新的线程池和进程池,之前我们说的进程池是在multiprocessing里面的,现在这个在这个新的模块里面,他俩用法上是一样的。 而且只要通过这个concurrent.futures导入就可以直接用他们两个了。

# 基本方法
#submit(fn, *args, **kwargs)
异步提交任务

#map(func, *iterables, timeout=None, chunksize=1) 
取代for循环submit的操作

#shutdown(wait=True) 
相当于进程池的pool.close()+pool.join()操作
wait=True,等待池内所有任务执行完毕回收完资源后才继续
wait=False,立即返回,并不会等待池内的任务执行完毕
但不管wait参数为何值,整个程序都会等到所有任务执行完毕
submit和map必须在shutdown之前

#result(timeout=None)
取得结果

#add_done_callback(fn)
回调函数

 简单的进程池的例子:

import os
import random
import time

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor

def task():
    print(f'{os.getpid()} 来了')
    time.sleep(random.randint(1,3))


if __name__ == '__main__':
    p = ProcessPoolExecutor()
    for i in range(20):
        p.submit(task,)

#输出
201 来了
202 来了
203 来了
204 来了
205 来了
206 来了
207 来了
208 来了
206 来了
208 来了
201 来了
203 来了
205 来了
202 来了
204 来了
207 来了
208 来了
206 来了
205 来了
208 来了

我电脑是8核的,可以看到开启了8个进程。

开线程只需要将ProcessPoolExecutor改成ThreadPoolExecutor即可。

下面看一下线程的例子:

import time
import os
import threading
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

def func(n):
    time.sleep(2)
    print('%s打印的:' % (threading.get_ident()), n)
    return n * n

tpool = ThreadPoolExecutor(max_workers=5)

t_lst = []
for i in range(5):
    t = tpool.submit(func, i)
    t_lst.append(t) # 注意这里不能直接打印t.result() 这样会变成串行

tpool.shutdown()
print('主线程')

for t in t_lst:
    print('result', t.result())

# 输出:
140412026685184打印的: 0
140411943192320打印的: 1
140411934738176打印的: 2
140411926284032打印的: 3
140411917829888打印的: 4
主线程
result 0
result 1
result 4
result 9
result 16

只要我们submit,就创建一个线程。shutdown则会关闭,但最终 都会等线程把任务执行完毕,并返回结果。

 

map的使用实例:这里把导入模块部分省略了

def task(n):
    print('%s is runing' % threading.get_ident())
    time.sleep(random.randint(1, 3))
    return n**2

if __name__ == '__main__':

    executor = ThreadPoolExecutor(max_workers=3)

    # for i in range(11):
    #     future=executor.submit(task,i)

    s = executor.map(task, range(1, 5))  # map取代了for+submit
    print([i for i in s])

其实这里的map 就是直到映射的作用,并没有什么特殊的,就是ducktype

至于回调函数就更好理解了,执行完后回调另一个函数来处理

def func(n):
    time.sleep(2)
    return n * n

def call_back(m):
    print('结果为:%s' % (m.result()))

tpool = ThreadPoolExecutor(max_workers=5)
t_lst = []
for i in range(5):
    t = tpool.submit(func, i).add_done_callback(call_back)

# 输出,这里的回调函数起到打印出结果的作用
结果为:0
结果为:1
结果为:9
结果为:4
结果为:16

在实际应用中,比如我们抓取网页,拿回网页的结果后需要调用相应的函数去对原始数据进行处理,就可以把后面这个处理的函数放在callback。

 

上一篇:Python 线程锁

下一篇:Python 协程