Python中的进程池与线程池

  • 引入进程池与线程池

  • 使用ProcessPoolExecutor进程池,使用ThreadPoolExecutor

  • 使用shutdown

  • 使用submit同步调用

  • 使用submit异步调用

  • 异步+回调函数

  • 并发实现套接字通信

引入进程池

在学习线程池之前,我们先看一个例子

 1 # from multiprocessing import Process
2 # import time
3 #
4 # def task(name):
5 # print('name',name)
6 # time.sleep(1)
7 # if __name__ == '__main__':
8 # start=time.time()
9 # p1 = Process(target=task,args=("safly1",))
10 # p2 = Process(target=task, args=("safly2",))
11 # p3 = Process(target=task, args=("safly3",))
12 #
13 # p1.start()
14 # p2.start()
15 # p3.start()
16 #
17 # p1.join()
18 # p2.join()
19 # p3.join()
20 #
21 # print("main")
22 #
23 # end = time.time()
24 # print(end- start)

输出如下:

以上的方式是一个个创建进程,这样的耗费时间才1秒多,虽然高效,但是有什么弊端呢? 
如果并发很大的话,会给服务器带来很大的压力,所以引入了进程池的概念

使用ProcessPoolExecutor进程池

什么时候用池:
池的功能是限制启动的进程数或线程数,
什么时候应该限制???
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时
就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内

Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的进一步抽象,对编写线程池/进程池提供了直接的支持。

通过ProcessPoolExecutor 来做示例。 
我们来看一个最简单的进程池

 1 from concurrent.futures import ProcessPoolExecutor
2 import time
3 def task(name):
4 print('name',name)
5 time.sleep(1)
6 if __name__ == '__main__':
7 start=time.time()
8 p1=ProcessPoolExecutor(2)
9 for i in range(5):
10 p1.submit(task,i)
11 p1.shutdown(wait=True)
12 print('主')
13 end=time.time()
14 print(end-start)

输出如下:

 1 D:\APPS\Python3.7\python.exe "D:/Python/project one/day20180717/进程池与线程池.py"
2 name 0
3 name 1
4 name 2
5 name 3
6 name 4
7 主
8 3.118098258972168
9
10 Process finished with exit code 0

简单解释下: 
ProcessPoolExecutor(2)创建一个进程池,容量为2,循环submit出5个进程,然后就在线程池队列里面,执行多个进程,p1.shutdown(wait=True)意思是进程都执行完毕,在执行主进程的内容

使用shutdown

p1.shutdown(wait=True)是进程池内部的进程都执行完毕,才会关闭,然后执行后续代码 
如果改成false呢?看如下代码

 1 from concurrent.futures import ProcessPoolExecutor
2 import time
3 def task(name):
4 print('name',name)
5 time.sleep(1)
6 if __name__ == '__main__':
7 start=time.time()
8 p1=ProcessPoolExecutor(2)
9 for i in range(5):
10 p1.submit(task,i)
11 p1.shutdown(wait=False)
12 print('主')
13 end=time.time()
14 print(end-start)

输出如下:

 1 D:\APPS\Python3.7\python.exe "D:/Python/project one/day20180717/进程池与线程池.py"
2 主
3 0.008975744247436523
4 name 0
5 name 1
6 name 2
7 name 3
8 name 4
9
10 Process finished with exit code 0

使用submit同步调用

同步:提交完任务后就在原地等待,直到任务运行完毕并且拿到返回值后,才运行下一行代码

from concurrent.futures import ProcessPoolExecutor
import time, random, os def piao(name, n):
print('%s is piaoing %s' % (name, os.getpid()))
time.sleep(1)
return n ** 2 if __name__ == '__main__':
p = ProcessPoolExecutor(2)
start = time.time()
for i in range(5):
res=p.submit(piao,'safly %s' %i,i).result() #同步调用
print(res) p.shutdown(wait=True)
print('主', os.getpid()) stop = time.time()
print(stop - start)
 1 D:\APPS\Python3.7\python.exe "D:/Python/project one/day20180717/进程池与线程池.py"
2 safly 0 is piaoing 11448
3 0
4 safly 1 is piaoing 11800
5 1
6 safly 2 is piaoing 11448
7 4
8 safly 3 is piaoing 11800
9 9
10 safly 4 is piaoing 11448
11 16
12 主 8516
13 5.095325946807861
14
15 Process finished with exit code 0

使用submit异步调用

异步:提交完任务(绑定一个回调函数)后不原地等待,直接运行下一行代码,等到任务运行有返回值自动触发回调的函数的运行

 1 from concurrent.futures import ThreadPoolExecutor
2 import time
3 def task(name):
4 print('name',name)
5 time.sleep(1)
6 if __name__ == '__main__':
7 start=time.time()
8 p1=ThreadPoolExecutor(2)
9 for i in range(5):
10 p1.submit(task,i)
11 p1.shutdown(wait=True)
12 print('主')
13 end=time.time()
14 print(end-start)
1 D:\APPS\Python3.7\python.exe "D:/Python/project one/day20180717/进程池与线程池.py"
2 name 0
3 name 1
4 name 2
5 name 3
6 name 4
7 主
8 3.003053903579712

使用回调函数+异步

进程

# from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# import os
# import time
# import random
#
# def task(n):
# print('%s run...' %os.getpid())
# time.sleep(5)
# return n**2
#
# def parse(future):
# time.sleep(1)
# res=future.result()
# print('%s 处理了 %s' %(os.getpid(),res))
#
# if __name__ == '__main__':
# pool=ProcessPoolExecutor(4)
# # pool.submit(task,1)
# # pool.submit(task,2)
# # pool.submit(task,3)
# # pool.submit(task,4)
#
# start=time.time()
# for i in range(1,5):
# future=pool.submit(task,i)
# future.add_done_callback(parse) # parse会在futrue有返回值时立刻触发,并且将future当作参数传给parse
# pool.shutdown(wait=True)
# stop=time.time()
# print('主',os.getpid(),(stop - start))
 1 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
2 from threading import current_thread
3 import os
4 import time
5 import random
6
7 def task(n):
8 print('%s run...' %current_thread().name)
9 time.sleep(5)
10 return n**2
11
12 def parse(future):
13 time.sleep(1)
14 res=future.result()
15 print('%s 处理了 %s' %(current_thread().name,res))
16
17 if __name__ == '__main__':
18 pool=ThreadPoolExecutor(4)
19 start=time.time()
20 for i in range(1,5):
21 future=pool.submit(task,i)
22 future.add_done_callback(parse) # parse会在futrue有返回值时立刻触发,并且将future当作参数传给parse
23 pool.shutdown(wait=True)
24 stop=time.time()
25 print('主',current_thread().name,(stop - start))

并发实现套接字通信

服务端
客户端

扩展:

回调函数(callback)是什么?

以下均来自知乎:

Python中的进程池与线程池(包含代码)的更多相关文章

  1. Python中的进程池与线程池

    引入进程池与线程池 使用ProcessPoolExecutor进程池,使用ThreadPoolExecutor 使用shutdown 使用submit同步调用 使用submit异步调用 异步+回调函数 ...

  2. python中的进程池

    1.进程池的概念 python中,进程池内部会维护一个进程序列.当需要时,程序会去进程池中获取一个进程. 如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止. 2.进程池 ...

  3. python系列之 - 并发编程(进程池,线程池,协程)

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  4. python并发编程之进程池,线程池,协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  5. python并发编程之进程池,线程池concurrent.futures

    进程池与线程池 在刚开始学多进程或多线程时,我们迫不及待地基于多进程或多线程实现并发的套接字通信,然而这种实现方式的致命缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多, 这会对 ...

  6. Python并发编程之进程池与线程池

    一.进程池与线程池 python标准模块concurrent.futures(并发未来) 1.concurrent.futures模块是用来创建并行的任务,提供了更高级别的接口,为了异步执行调用 2. ...

  7. python 36 进程池、线程池

    目录 1. 死锁与递归锁 2. 信号量Semaphor 3. GIL全局解释器锁:(Cpython) 4. IO.计算密集型对比 4.1 计算密集型: 4.2 IO密集型 5. GIL与Lock锁的区 ...

  8. python并发编程之进程池、线程池、协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  9. GIL全局解释器锁、死锁现象、python多线程的用处、进程池与线程池理论

    昨日内容回顾 僵尸进程与孤儿进程 # 僵尸进程: 所有的进程在运行结束之后并不会立刻销毁(父进程需要获取该进程的资源) # 孤儿进程: 子进程正常运行 但是产生该子进程的父进程意外死亡 # 守护进程: ...

随机推荐

  1. 02_jQuery对象初识(二)筛选器1

    0. HTML对象和jQuery对象的区别: 1.jQuery对象转换成DOM对象,用索引取出具体的标签 2.DOM对象转换成jQuery对象,$(DOM对象) 注意:jQuery对象保存到变量的时候 ...

  2. Could not resolve placeholder 'CUST_INDUSTORY' in string value "${CUST_INDUSTORY}"

    问题描述 项目中的资源文件中写了个properties文件,内容这样的 CUST_FROM=002 CUST_INDUSTORY=001 CUST_LEVEL=006 在springmvc配置文件中加 ...

  3. windows 常用的快捷键

    记录一些 windows 常用快捷键,待更新 Ctrl系列 快捷键 功能 Ctrl + C 复制 Ctrl + INSERT 复制 Ctrl + V 粘贴 Ctrl + Z 撤销 Ctrl + D 删 ...

  4. Windows API 第15篇 GetVolumeInformation 获取磁盘卷(驱动器)信息

    先看定义:BOOL GetVolumeInformation(    [IN]  LPCTSTR lpRootPathName,           // root directory  卷所在的根目 ...

  5. (补充)06.Hibernate持久化类&持久化对象

    持久化类:就是一个Java类(JavaBean),这个类与表建立映射关系就可以成为是持久类 持久化类 = JavaBean + xxx.hbm.xml 编写规则: 1.提供一个无参数,public访问 ...

  6. MaxCompute问答整理之8月

    本文是基于对MaxCompute产品的学习进度,再结合开发者社区里面的一些问题,进而整理成文.希望对大家有所帮助. 问题一.通过数据源数据增量同步后,如何查看某一条数据具体被同步到MaxCompute ...

  7. 子类A继承父类B, A a = new A(); 则父类B构造函数、父类B静态代码块、父类B非静态代码块、子类A构造函数、子类A静态代码块、子类A非静态代码块 执行的先后顺序是

    按照先后顺序: 1,静态先于非静态代码库执行(静态代码块随着类的加载而加载,初始化只执行一次) 2,父类先于子类 3,非静态代码块优于构造函数执行 所以执行顺序如下: 父类B静态代码块->子类A ...

  8. vue.js_08_vue-组件的定义

    1.vue组件常用定义方式 <body> <div id="app"> <!--1.3使用组件--> <mycom1></my ...

  9. php表单 - 验证邮件和URL

    PHP - 验证名称 以下代码将通过简单的方式来检测 name 字段是否包含字母和空格,如果 name 字段值不合法,将输出错误信息: $name = test_input($_POST[" ...

  10. linux负载均衡(什么是负载均衡)

    linux负载均衡(什么是负载均衡) 一.总结 一句话总结: 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用 ...