一、进程池与线程池介绍
池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时就应该用池的概念将开启的进程数或线程数
池子内什么时候装进程:并发的任务属于计算密集型池子内什么时候装线程:并发的任务属于IO密集型
不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池。其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉
只要你用并发,就会有锁的问题,但是你不能一直去自己加锁吧那么我们就用QUEUE,这样还解决了自动加锁的问题由Queue延伸出的一个点也非常重要的概念。以后写程序也会用到这个思想。就是生产者与消费者问题
二、Python标准模块--concurrent.futures(并发未来)
concurent.future模块需要了解的1.concurent.future模块是用来创建并行的任务,提供了更高级别的接口,为了异步执行调用2.concurent.future这个模块用起来非常方便,它的接口也封装的非常简单3.concurent.future模块既可以实现进程池,也可以实现线程池4.模块导入进程池和线程池from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor还可以导入一个Executor,但是你别这样导,这个类是一个抽象类抽象类的目的是规范他的子类必须有某种方法(并且抽象类的方法必须实现),但是抽象类不能被实例化5.p = ProcessPoolExecutor(max_works)对于进程池如果不写max_works:默认的是cpu的数目,默认是4个p = ThreadPoolExecutor(max_works)对于线程池如果不写max_works:默认的是cpu的数目*56.如果是进程池,得到的结果如果是一个对象。我们得用一个.get()方法得到结果但是现在用了concurent.future模块,我们可以用obj.result方法p.submit(task,i) #相当于apply_async异步方法p.shutdown() #默认有个参数wite=True (相当于close和join)
那么什么是线程池呢?我们来了解一下
三、线程池
进程池:就是在一个进程内控制一定个数的线程基于concurent.future模块的进程池和线程池 (他们的同步执行和异步执行是一样的)
# 1.同步执行--------------
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os,time,random
def task(n):
print('[%s] is running'%os.getpid())
time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长
return n**2
if __name__ == '__main__':
start = time.time()
p = ProcessPoolExecutor()
for i in range(10): #现在是开了10个任务, 那么如果是上百个任务呢,就不能无线的开进程,那么就得考虑控制
# 线程数了,那么就得考虑到池了
obj = p.submit(task,i).result() #相当于apply同步方法
p.shutdown() #相当于close和join方法
print('='*30)
print(time.time() - start) #17.36499309539795
# 2.异步执行-----------
# from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# import os,time,random
# def task(n):
# print('[%s] is running'%os.getpid())
# time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长
# return n**2
# if __name__ == '__main__':
# start = time.time()
# p = ProcessPoolExecutor()
# l = []
# for i in range(10): #现在是开了10个任务, 那么如果是上百个任务呢,就不能无线的开进程,那么就得考虑控制
# # 线程数了,那么就得考虑到池了
# obj = p.submit(task,i) #相当于apply_async()异步方法
# l.append(obj)
# p.shutdown() #相当于close和join方法
# print('='*30)
# print([obj.result() for obj in l])
# print(time.time() - start) #5.362306594848633
基于concurrent.futures模块的进程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
import os,time,random
def task(n):
print('%s:%s is running'%(currentThread().getName(),os.getpid())) #看到的pid都是一样的,因为线程是共享了一个进程
time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长
return n**2
if __name__ == '__main__':
start = time.time()
p = ThreadPoolExecutor() #线程池 #如果不给定值,默认cup*5
l = []
for i in range(10): #10个任务 # 线程池效率高了
obj = p.submit(task,i) #相当于apply_async异步方法
l.append(obj)
p.shutdown() #默认有个参数wite=True (相当于close和join)
print('='*30)
print([obj.result() for obj in l])
print(time.time() - start) #3.001171827316284
基于concurrent.futures模块的线程池
应用线程池(下载网页并解析)
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import requests
import time,os
def get_page(url):
print('<%s> is getting [%s]'%(os.getpid(),url))
response = requests.get(url)
if response.status_code==200: #200代表状态:下载成功了
return {'url':url,'text':response.text}
def parse_page(res):
res = res.result()
print('<%s> is getting [%s]'%(os.getpid(),res['url']))
with open('db.txt','a') as f:
parse_res = 'url:%s size:%s\n'%(res['url'],len(res['text']))
f.write(parse_res)
if __name__ == '__main__':
# p = ThreadPoolExecutor()
p = ProcessPoolExecutor()
l = [
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
]
for url in l:
res = p.submit(get_page,url).add_done_callback(parse_page) #这里的回调函数拿到的是一个对象。得
# 先把返回的res得到一个结果。即在前面加上一个res.result() #谁好了谁去掉回调函数
# 回调函数也是一种编程思想。不仅开线程池用,开线程池也用
p.shutdown() #相当于进程池里的close和join
print('主',os.getpid())
map函数的应用
# map函数举例
obj= map(lambda x:x**2 ,range(10))
print(list(obj))
#运行结果[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
可以和上面的开进程池/线程池的对比着看,就能发现map函数的强大了
# 我们的那个p.submit(task,i)和map函数的原理类似。我们就
# 可以用map函数去代替。更减缩了代码
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os,time,random
def task(n):
print('[%s] is running'%os.getpid())
time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长
return n**2
if __name__ == '__main__':
p = ProcessPoolExecutor()
obj = p.map(task,range(10))
p.shutdown() #相当于close和join方法
print('='*30)
print(obj) #返回的是一个迭代器
print(list(obj))
map函数应用