python 命令行运行 多进程_Python初学——多进程Multiprocessing
1.1 什么是 Multiprocessing
多线程在同一时间只能处理一个任务。
可把任务平均分配给每个核,而每个核具有自己的运算空间。
1.2 添加进程 Process
与线程类似,如下所示,但是该程序直接运行无结果,因为IDLE不支持多进程,在命令行终端运行才有结果显示
importmultiprocessing as mpdefjob(a,b):print('abc')if __name__=='__main__':
p1=mp.Process(target=job,args=(1,2))
p1.start()
p1.join()
1.3 存储进程输出 Queue
不知道为什么下面的这个程序可以在IDLE中正常运行。首先定义了一个job函数作系列数学运算,然后将结果放到res中,在main函数运行,取出queue中存储的结果再进行一次加法运算。
importmultiprocessing as mpdefjob(q):
res=0for i in range(1000):
res+=i+i**2+i**3q.put(res)if __name__ == '__main__':
q=mp.Queue()
p1= mp.Process(target=job,args=(q,))#注意当参数只有一个时,应加上逗号
p2 = mp.Process(target=job,args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
res1=q.get()
res2=q.get()print(res1+res2)
结果如下所示:
1.4 效率比对 threading & multiprocessing
在job函数中定义了数学运算,比较正常情况、多线程和多进程分别的运行时间。
importmultiprocessing as mpimportthreading as tdimporttimedefjob(q):
res=0for i in range(10000000):
res+= i+i**2+i**3q.put(res)#queue
defmulticore():
q=mp.Queue()
p1= mp.Process(target=job, args=(q,))
p2= mp.Process(target=job, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
res1=q.get()
res2=q.get()print('multicore:' , res1+res2)defnormal():
res=0for _ in range(2):#线程或进程都构造了两个,进行了两次运算,所以这里循环两次
for i in range(10000000):
res+= i+i**2+i**3
print('normal:', res)defmultithread():
q=mp.Queue()
t1= td.Thread(target=job, args=(q,))
t2= td.Thread(target=job, args=(q,))
t1.start()
t2.start()
t1.join()
t2.join()
res1=q.get()
res2=q.get()print('multithread:', res1+res2)if __name__ == '__main__':
st=time.time()
normal()
st1=time.time()print('normal time:', st1 -st)
multithread()
st2=time.time()print('multithread time:', st2 -st1)
multicore()print('multicore time:', time.time()-st2)
在视频中的运行结果是多进程
综上,多核/多进程运行最快,说明在同时间运行了多个任务,而多线程却不一定会比正常情况下的运行来的快,这和多线程中的GIL有关。
1.5 进程池
进程池Pool,就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题。
importmultiprocessing as mpdefjob(x):return x*xdefmulticore():
pool=mp.Pool(processes=2)#定义一个Pool,并定义CPU核数量为2
res=pool.map(job,range(10))print(res)
res=pool.apply_async(job,(2,))print(res.get())
multi_res=[pool.apply_async(job,(i,)) for i in range(10)]print([res.get()for res inmulti_res])if __name__=='__main__':
multicore()
运行结果如下所示:
首先定义一个池子,有了池子之后,就可以让池子对应某一个函数,在上述代码中定义的pool对应job函数。我们向池子里丢数据,池子就会返回函数返回的值。 Pool和之前的Process的不同点是丢向Pool的函数有返回值,而Process的没有返回值。
接下来用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果
我们怎么知道Pool是否真的调用了多个核呢?我们可以把迭代次数增大些,然后打开CPU负载看下CPU运行情况
打开CPU负载(Mac):活动监视器 > CPU > CPU负载(单击一下即可)
Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数即可自定义需要的核数量。
Pool除了可以用map来返回结果之外,还可以用apply_async(),与map不同的是,只能传递一个值,只会放入一个核进行计算,但是传入值时要注意是可迭代的,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值。所对应的代码为:
res=pool.apply_async(job,(2,))print(res.get())
运行结果为4。
由于传入值是可以迭代的,则我们同样可以使用apply_async()来输出多个结果。如果在apply_async()中输入多个传入值:
res = pool.apply_async(job, (2,3,4,))
结果会报错:
TypeError: job() takes exactly 1 argument (3 given)
即apply_async()只能输入一组参数。
在此我们将apply_async()放入迭代器中,定义一个新的multi_res
multi_res = [pool.apply_async(job, (i,)) for i in range(10)]
同样在取出值时需要一个一个取出来
print([res.get() for res in multi_res])
apply用迭代器的运行结果与map取出的结果相同。
note:
(1)Pool默认调用是CPU的核数,传入processes参数可自定义CPU核数
(2)map() 放入迭代参数,返回多个结果
(3)apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代
1.6 共享内存 shared memory
只有通过共享内存才能让CPU之间进行交流。
通过Value将数据存储在一个共享的内存表中。
importmultiprocessing as mp
value1= mp.Value('i', 0)
value2= mp.Value('d', 3.14)
其中,i和d表示数据类型。i为带符号的整型,d为双精浮点类型。更多数据类型可参考网址:https://docs.python.org/3/library/array.html
在多进程中有一个Array类,可以和共享内存交互,来实现进程之间共享数据。
和numpy中的不同,这里的Array只能是一维的,并且需要定义数据类型否则会报错。
array = mp.Array('i', [1, 2, 3, 4])
1.7 进程锁 Lock
首先是不加进程锁的运行情况,在下述代码中定义了共享变量v,定义了两个进程,均可对v进行操作。job函数的作用是每隔0.1s输出一次累加num的值,累加值num在两个进程中分别为1和3。
importmultiprocessing as mpimporttimedefjob(v,num):for _ in range(10):
time.sleep(0.1)#暂停0.1s,让输出效果更明显
v.value+=num #v.value获取共享变量值
print(v.value)defmulticore():
v=mp.Value('i',0)#定义共享变量
p1=mp.Process(target=job,args=(v,1))
p2=mp.Process(target=job,args=(v,3))
p1.start()
p2.start()
p1.join()
p2.join()if __name__=='__main__':
multicore()
运行结果如下所示:
可以看到两个进程互相抢占共享内存v。
为了解决上述不同进程抢共享资源的问题,我们可以用加进程锁来解决。
首先需要定义一个进程锁:
l = mp.Lock() #定义一个进程锁
然后将进程锁的信息传入各个进程中
p1 = mp.Process(target=job, args=(v,1,l)) #需要将Lock传入
p2 = mp.Process(target=job, args=(v,3,l))
在job()中设置进程锁的使用,保证运行时一个进程的对锁内内容的独占
defjob(v, num, l):
l.acquire()#锁住
for _ in range(5):
time.sleep(0.1)
v.value+= num #v.value获取共享内存
print(v.value)
l.release()#释放
完整代码:
defjob(v, num, l):
l.acquire()#锁住
for _ in range(5):
time.sleep(0.1)
v.value+= num #获取共享内存
print(v.value)
l.release()#释放
defmulticore():
l= mp.Lock() #定义一个进程锁
v = mp.Value('i', 0) #定义共享内存
p1 = mp.Process(target=job, args=(v,1,l)) #需要将lock传入
p2 = mp.Process(target=job, args=(v,3,l))
p1.start()
p2.start()
p1.join()
p2.join()if __name__ == '__main__':
multicore()
运行结果如下所示:
可以看到进程1运行完之后才运行进程2。
python 命令行运行 多进程_Python初学——多进程Multiprocessing相关推荐
- python命令行运行django项目, can‘t open file ‘manage.py‘ 问题解决
python命令行运行django项目, can't open file 'manage.py' 问题解决 参考文章: (1)python命令行运行django项目, can't open file ...
- python 命令行解析模块_Python命令行解析模块详解
python2.7 怎么解析命令行输入的中文参数 本文实例讲述了python读取命令行参数的方法.分享给大家供大家参考.具体分析如下: 如果想对python脚本传参数,python中对应的argc, ...
- python命令行参数 空格_Python 命令行参数
Python 命令行参数 Python 提供了 getopt 模块来获取命令行参数. $ python test.py arg1 arg2 arg3 Python 中也可以使用 sys 的 sys.a ...
- python 命令行解析模块_Python解析命令行读取参数 -- argparse模块
在多个文件或者不同语言协同的项目中,python脚本经常需要从命令行直接读取参数.万能的python就自带了argprase包使得这一工作变得简单而规范.PS:optparse包是类似的功能,只不过写 ...
- python命令行输入参数_Python命令行参数处理
sys模块 sys模块代表了Python解释器,主要用于获取和Python解释器相关的信息,其中 sys.argv 可以获取命令行参数 在Python交互式解释器中可以先导入sys模块 import ...
- python命令行运行找不到自定义模块
报错ImportError: No module named 'XXX' 可能小伙伴们在pycharm运行一切正常,但是到命令行中运行py文件,就会报错. 在python中,一个py文件就是一个模块, ...
- python命令行参数作用_Python命令行参数解析模块argparse
前言 更多内容,请访问我的 个人博客. 以前 optparse 比较火,但是在python2.7版本后,官方不再维护这个模块,转而大力支持 argparse . argparse 模块可以让人轻松编写 ...
- python命令行参数 空格_Python - 命令行参数
前言 每个脚本或者命令行程序都可以输入一些参数,通常有两种规范. 短格式,"-"号后面要紧跟一个选项字母,如果还有此选项的附加参数,可以用空格分开,也可以不分开,长度任意,可以用引 ...
- python命令行下载文件_python写的批量操作远程主机脚本(命令执行,上传、下载文件)...
最近在学习python,借助fabric模块写了个批量操作服务器的脚本,在此分享给大家,如有不足之处,欢迎大家指正 准备工作: 安装python 2.6.5: yum -y install readl ...
最新文章
- android筛选cookie,服务器无法从Android手机识别Cookie
- Spring Boot 2.x中如何使用Log4j2记录日志
- JavaWeb中使用session保持用户登录状态
- Android aidl在Framework的使用
- Flask简介与简单项目操作流程
- leetcode 100.Same Tree
- c语言用户管理系统的知识,C语言系统用户管理系统
- 【Java】java LinkedTransferQueue 介绍
- 无法启动此程序 因为计算机中丢失 msvcp71.dll,msvcp71.dll丢失怎样修复?计算机中丢失msvcp71.dll文件的解决方法...
- 微服务实战(六):选择微服务部署策略 - DockOne.io
- linux ln mysql.sock_linux中MySQL连接找不到mysql.sock文件
- 尽在双11:阿里巴巴技术演进与超越
- 高斯过程回归预测Matlab简单实现
- 个人信息安全规范----2、个人信息安全基本原则
- diy服务器个人主机_DIY个人服务器
- windows无法完成更新正在撤销更改
- 自媒体推广该怎么做?学懂这10招,走路横着走
- 不要自己默默加班了!争取领导支援的五大实战话术
- 闲来没事学Dart(七)函数
- 【读书笔记】《刻意练习》 [美] 安德斯·艾利克森(Anders Ericsson)