进程池/线程池
开进程开线程都需要消耗资源,只不过两者比较的情况下线程的资源消耗的较小
所以我们要在计算机能够承受的范围内最大限度的利用计算机
池 :
在保证计算机硬件的安全情况下最大限度的利用计算机的资源
池其实是江都了程序的运行效率,但是保证了计算机永健的安全
concurrent.futures 模块
pool = ProcessPoolExecutor() 进程池 括号内可以传参数指定进程个数,默认cpu个数
pool = ThreadPoolExecutor() 线程池 括号内可以传参数指定线程个数,默认cpu*5个
池子中创建的进程/线程创建一次就不会创建了,至始至终用的都是最初的默认或自定义的那几个,这样节省了反复开辟进程/线程资源
pool.submit(fn, *args, **kwargs ) 向线程/进程内提交任务 异步提交
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor import os import time # 实例化进程池 pool = ProcessPoolExecutor() # 括号内可以传参数指定池的个数,进程池默认是cpu个数 # 实例化线程池 # pool = ThreadPoolExecutor() def task(n): print('%s running'%n, os.getpid()) time.sleep(3) print('%s over'%n) return n**2 if __name__ == '__main__': pool.submit(task, 1) # 向进程池/线程池内提交任务 异步提交 print('主 进程/线程')
result() 原地等待任务的返回结果
# 实例化进程池 # pool = ProcessPoolExecutor() # 实例化线程池 pool = ThreadPoolExecutor(5) def task(n): print('%s running'%n, os.getpid()) time.sleep(3) # print('%s over'%n) return n**2 if __name__ == '__main__': for i in range(3): res = pool.submit(task, i) print('>>>:', res.result()) # 原地等待任务的返回结果(return 的结果) >>> 0 running 3664 >>>:0 1 running 3664 >>>:1 2 running 3664 >>>:4
pool.shutdown() 关闭池子,等待池子中的所有任务执行完毕后再走下面得我代码
pool = ThreadPoolExecutor(5) def task(n): print('%s running'%n, os.getpid()) time.sleep(3) # print('%s over'%n) return n**2 if __name__ == '__main__': lists = [] for i in range(3): res = pool.submit(task, i) # 异步提交任务 lists.append(res) pool.shutdown() # 关闭池子,等待池子中的所有任务执行完毕后再走下面得代码 for p in lists: print('>>>:', p.result()) >>> 0 running 12168 1 running 12168 2 running 12168 >>>: 0 >>>: 1 >>>: 4
add_done_callback (func) 回调函数
# 实例化进程池 # pool = ProcessPoolExecutor() # 实例化线程池 pool = ThreadPoolExecutor(5) def task(n): print('%s running'%n, os.getpid()) time.sleep(3) # print('%s over'%n) return n**2 def call_back(n): print('异步提交任务的返回结果:', n.result()) if __name__ == '__main__': for i in range(10): res = pool.submit(task, i).add_done_callback(call_back) # 提交任务的时候,绑定一个回调函数,一旦该任务有结果,立刻执行对应的回调函数 >>> 0 running 8488 1 running 8488 2 running 8488 3 running 8488 4 running 8488 异步提交任务的返回结果: 0 5 running 8488 异步提交任务的返回结果: 1 6 running 8488 异步提交任务的返回结果: 4 7 running 8488 异步提交任务的返回结果: 9 8 running 8488 异步提交任务的返回结果: 16 9 running 8488 异步提交任务的返回结果: 36 异步提交任务的返回结果: 25 异步提交任务的返回结果: 64 异步提交任务的返回结果: 49 异步提交任务的返回结果: 81
协程
进程: 资源单位 线程: 执行单位 协程: 单线程下实现并发 并发: 切换 + 保存状态 CPU正在运行一个任务,会在两种情况下切走取执行其他任务(切换有操作系统强行控制) 1.该任务遇到了阻塞 2.该任务计算时间过长
协程的本质就是在单线程下,由用户自己通过代码控制一个任务遇到IO阻塞了就切换到另一个任务去执行,以此来提升效率,给操作系统的感觉是你这个线程没有任何的IO(而是在来回切换),从而保证程序在 就绪态 运行态来回切换.
为了实现它,我们需要找寻一种可以同时满足控制多个任务切换和雀环之前保存状态的解决方案.
gevent 模块
from gevent import spawn from gevent import monkey;monkey.patch_all() import time ''' gevent 模块无法识别time.sleep等io情况 所以需要手动配置monkey.patch_all() ''' def heng(name): print('%s'%name, '哼') time.sleep(2) print('%s'%name, '哼') def ha(name): print('%s'%name, '哈') time.sleep(3) print('%s'%name, '哈') start = time.time() # 创建协程对象 spawn参数一是执行函数的名,参数二是函数需要的参数 g1 = spawn(heng, 'x') g2 = spawn(ha, 'y') g1.join() # 等待g1运行结束 g2.join() print(time.time() - start)