进程池
为什么会有进程池的概念:
进程过多,操作系统的调度会很耗时,效率低。
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池内没有可供使用的进程,那么程序就会等待,直到进程池中有可用的进程为止。
进程池和信号量的区别:
进程池是先创建5个进程,然后200个任务排队,同时只有5个任务执行。
信号量是先创建200个进程,同时有5个进程执行。
进程池相对于信号量的优点:
1、节省了195个进程的创建时间
2、节省了195个进程的内存占用
3、节省了操作系统对195个进程的调度时间
更高级的进程池
进程池的大小在n到m之间。适用于高峰期和低峰期。
优点:高峰期增加并发量。低峰期回收不用的进程。
from multiprocessing import Process, Pool
import time
def func(n):
print('start %s' %(n))
time.sleep(1)
print('end %s' %(n))
if __name__ =='__main__':
pool = Pool(5)
for i in range(10):
pool.apply_async(func, args=(i,))
pool.close()
pool.join()
进程池的返回值
一、p.map(funcname, iterable) 默认异步的执行任务,且自带close和join
(1)返回值是所有进程的结果放到一个列表里
二、p.apply() 同步调用的,很少用
(1)只有func执行完之后,才会继续向下执行其他代码
(2)返回值就是func的返回值
三、p.apply_async() 异步调用,和主进程完全异步,需要手动close和join
(1) 异步的:当func被注册进入一个进程之后,程序就继续向下执行
(2) -返回值:返回一个对象,可以从对象里获取func函数的返回值obj.get,get会阻塞直到对应的func执行完毕拿到结果
(3) -使用apply_async给进程池分配任务
(4) -需要先close后join来保持多进程和主进程代码的同步性
1、apply_async异步
from multiprocessing import Pool
import time
def func(i):
time.sleep(1)
return i*i
if __name__ == '__main__':
p = Pool(5)
res_l = []
for i in range(10):
res = p.apply_async(func, args=(i,)) # apply_async的返回值就是函数func的返回值
res_l.append(res)
for res in res_l:
print(res.get()) # 等着func的计算结果,会进行阻塞
2、 map异步
from multiprocessing import Pool
import time
def func(i):
time.sleep(1)
return i*i
if __name__ == '__main__':
p = Pool(5)
res = p.map(func, range(10)) # map异步执行任务,自带close和join方法
print(res) # 所有任务都完成之后,返回一个所有结果的列表
进程池的回调函数
(1)回调函数是在主进程中执行
(2)子进程函数的返回值是回调函数的参数
(3)回调函数在爬虫的时候用的多,因为从网上下载延时最高的。用回调函数会节省下进程池的资源,用于下载。
(4)适用于回调函数执行任务的时间远远小于原函数执行的时间。
from multiprocessing import Pool
import os
def func1(n):
print('in func1', os.getpid())
return n*n
def func2(nn):
print('in func2', os.getpid()) # 回调函数在主进程里执行
print(nn)
if __name__ == '__main__':
print('主进程', os.getpid())
p = Pool(5)
for i in range(10):
p.apply_async(func1, args=(10,), callback=func2) # 回调函数的参数是func1函数的返回值
p.close()
p.join()
数据爬取中使用回调函数
import requests
from multiprocessing import Pool
def get(url):
response = requests.get(url)
if response.status_code == 200:
return url, response.content.decode('utf-8')
def call_back(args):
url, content = args
print(url, len(content))
if __name__ == '__main__':
url_l = [
'https://www.cnblogs.com/',
'http://www.baidu.com',
'http://www.sohu.com',
'https://www.sogou.com',
]
p = Pool(5)
for url in url_l:
p.apply_async(get, args=(url,), callback=call_back)
p.close()
p.join()
线程中的条件锁
acquire() release()
一个条件被创建之初,默认有一个FALSE状态
wait() #等待notify发放钥匙,发放几个,就走几个线程,钥匙不归还。在acquire和release之间
FALSE状态,会影wait一直处于等待状态
notify(int数据类型) 制作钥匙
线程池
from concurrent.futures import ThreadPoolExecutor
import time
def func(n):
time.sleep(1)
print(n)
return n*n
tpool = ThreadPoolExecutor(max_workers=5)
# tpool.map(func, range(20)) # 拿不到返回值
t_lst = []
for i in range(20):
t = tpool.submit(func, i)
t_lst.append(t)
tpool.shutdown() # close和join的作用 close关闭线程池(不让别的任务进来) join线程池里面的线程执行完,加上这个效率低
print('主线程')
for t in t_lst:
print(t.result())
线程池中的回调函数
from concurrent.futures import ThreadPoolExecutor
import time
def func(n):
time.sleep(1)
print(n)
return n*n
def call_back(m):
print('结果是%s' % m.result())
tpool = ThreadPoolExecutor(max_workers=5)
# tpool.map(func, range(20)) # 拿不到返回值
t_lst = []
for i in range(20):
t = tpool.submit(func, i).add_done_callback(call_back)
t_lst.append(t)
# tpool.shutdown() # close和join的作用 close关闭线程池(不让别的任务进来) join线程池里面的线程执行完,加上这个效率低
print('主线程')
# for t in t_lst:
# print(t.result())