python并发编程之进程池,线程池
Posted IT_study
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python并发编程之进程池,线程池相关的知识,希望对你有一定的参考价值。
要注意一下
不能无限的开进程,不能无限的开线程
最常用的就是开进程池,开线程池。其中回调函数非常重要
回调函数其实可以作为一种编程思想,谁好了谁就去掉
只要你用并发,就会有锁的问题,但是你不能一直去自己加锁吧
那么我们就用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的数目*5
6.如果是进程池,得到的结果如果是一个对象。我们得用一个.get()方法得到结果
但是现在用了concurent.future模块,我们可以用obj.result方法
p.submit(task,i) #相当于apply_async异步方法
p.shutdown() #默认有个参数wite=True (相当于close和join)
二、线程池
进程池:就是在一个进程内控制一定个数的线程
基于concurent.future模块的进程池和线程池 (他们的同步执行和异步执行是一样的)
1 # 1.同步执行-------------- 2 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 3 import os,time,random 4 def task(n): 5 print(‘[%s] is running‘%os.getpid()) 6 time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长 7 return n**2 8 if __name__ == ‘__main__‘: 9 start = time.time() 10 p = ProcessPoolExecutor() 11 for i in range(10): #现在是开了10个任务, 那么如果是上百个任务呢,就不能无线的开进程,那么就得考虑控制 12 # 线程数了,那么就得考虑到池了 13 obj = p.submit(task,i).result() #相当于apply同步方法 14 p.shutdown() #相当于close和join方法 15 print(‘=‘*30) 16 print(time.time() - start) #17.36499309539795 17 18 19 # 2.异步执行----------- 20 # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 21 # import os,time,random 22 # def task(n): 23 # print(‘[%s] is running‘%os.getpid()) 24 # time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长 25 # return n**2 26 # if __name__ == ‘__main__‘: 27 # start = time.time() 28 # p = ProcessPoolExecutor() 29 # l = [] 30 # for i in range(10): #现在是开了10个任务, 那么如果是上百个任务呢,就不能无线的开进程,那么就得考虑控制 31 # # 线程数了,那么就得考虑到池了 32 # obj = p.submit(task,i) #相当于apply_async()异步方法 33 # l.append(obj) 34 # p.shutdown() #相当于close和join方法 35 # print(‘=‘*30) 36 # print([obj.result() for obj in l]) 37 # print(time.time() - start) #5.362306594848633
1 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 2 from threading import currentThread 3 import os,time,random 4 def task(n): 5 print(‘%s:%s is running‘%(currentThread().getName(),os.getpid())) #看到的pid都是一样的,因为线程是共享了一个进程 6 time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长 7 return n**2 8 if __name__ == ‘__main__‘: 9 start = time.time() 10 p = ThreadPoolExecutor() #线程池 #如果不给定值,默认cup*5 11 l = [] 12 for i in range(10): #10个任务 # 线程池效率高了 13 obj = p.submit(task,i) #相当于apply_async异步方法 14 l.append(obj) 15 p.shutdown() #默认有个参数wite=True (相当于close和join) 16 print(‘=‘*30) 17 print([obj.result() for obj in l]) 18 print(time.time() - start) #3.001171827316284
应用线程池
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 ‘%(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]
1 # 我们的那个p.submit(task,i)和map函数的原理类似。我们就 2 # 可以用map函数去代替。更减缩了代码 3 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 4 import os,time,random 5 def task(n): 6 print(‘[%s] is running‘%os.getpid()) 7 time.sleep(random.randint(1,3)) #I/O密集型的,,一般用线程,用了进程耗时长 8 return n**2 9 if __name__ == ‘__main__‘: 10 p = ProcessPoolExecutor() 11 obj = p.map(task,range(10)) 12 p.shutdown() #相当于close和join方法 13 print(‘=‘*30) 14 print(obj) #返回的是一个迭代器 15 print(list(obj))
以上是关于python并发编程之进程池,线程池的主要内容,如果未能解决你的问题,请参考以下文章
python 之 并发编程(进程池与线程池同步异步阻塞非阻塞线程queue)
Python并发编程之线程池/进程池--concurrent.futures模块
2020Python修炼记python并发编程补充—进程池和线程池