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相关推荐

  1. python命令行运行django项目, can‘t open file ‘manage.py‘ 问题解决

    python命令行运行django项目, can't open file 'manage.py' 问题解决 参考文章: (1)python命令行运行django项目, can't open file ...

  2. python 命令行解析模块_Python命令行解析模块详解

    python2.7 怎么解析命令行输入的中文参数 本文实例讲述了python读取命令行参数的方法.分享给大家供大家参考.具体分析如下: 如果想对python脚本传参数,python中对应的argc, ...

  3. python命令行参数 空格_Python 命令行参数

    Python 命令行参数 Python 提供了 getopt 模块来获取命令行参数. $ python test.py arg1 arg2 arg3 Python 中也可以使用 sys 的 sys.a ...

  4. python 命令行解析模块_Python解析命令行读取参数 -- argparse模块

    在多个文件或者不同语言协同的项目中,python脚本经常需要从命令行直接读取参数.万能的python就自带了argprase包使得这一工作变得简单而规范.PS:optparse包是类似的功能,只不过写 ...

  5. python命令行输入参数_Python命令行参数处理

    sys模块 sys模块代表了Python解释器,主要用于获取和Python解释器相关的信息,其中 sys.argv 可以获取命令行参数 在Python交互式解释器中可以先导入sys模块 import ...

  6. python命令行运行找不到自定义模块

    报错ImportError: No module named 'XXX' 可能小伙伴们在pycharm运行一切正常,但是到命令行中运行py文件,就会报错. 在python中,一个py文件就是一个模块, ...

  7. python命令行参数作用_Python命令行参数解析模块argparse

    前言 更多内容,请访问我的 个人博客. 以前 optparse 比较火,但是在python2.7版本后,官方不再维护这个模块,转而大力支持 argparse . argparse 模块可以让人轻松编写 ...

  8. python命令行参数 空格_Python - 命令行参数

    前言 每个脚本或者命令行程序都可以输入一些参数,通常有两种规范. 短格式,"-"号后面要紧跟一个选项字母,如果还有此选项的附加参数,可以用空格分开,也可以不分开,长度任意,可以用引 ...

  9. python命令行下载文件_python写的批量操作远程主机脚本(命令执行,上传、下载文件)...

    最近在学习python,借助fabric模块写了个批量操作服务器的脚本,在此分享给大家,如有不足之处,欢迎大家指正 准备工作: 安装python 2.6.5: yum -y install readl ...

最新文章

  1. android筛选cookie,服务器无法从Android手机识别Cookie
  2. Spring Boot 2.x中如何使用Log4j2记录日志
  3. JavaWeb中使用session保持用户登录状态
  4. Android aidl在Framework的使用
  5. Flask简介与简单项目操作流程
  6. leetcode 100.Same Tree
  7. c语言用户管理系统的知识,C语言系统用户管理系统
  8. 【Java】java LinkedTransferQueue 介绍
  9. 无法启动此程序 因为计算机中丢失 msvcp71.dll,msvcp71.dll丢失怎样修复?计算机中丢失msvcp71.dll文件的解决方法...
  10. 微服务实战(六):选择微服务部署策略 - DockOne.io
  11. linux ln mysql.sock_linux中MySQL连接找不到mysql.sock文件
  12. 尽在双11:阿里巴巴技术演进与超越
  13. 高斯过程回归预测Matlab简单实现
  14. 个人信息安全规范----2、个人信息安全基本原则
  15. diy服务器个人主机_DIY个人服务器
  16. windows无法完成更新正在撤销更改
  17. 自媒体推广该怎么做?学懂这10招,走路横着走
  18. 不要自己默默加班了!争取领导支援的五大实战话术
  19. 闲来没事学Dart(七)函数
  20. 【读书笔记】《刻意练习》 [美] 安德斯·艾利克森(Anders Ericsson)

热门文章

  1. 零基础学python-看完这篇,零基础也知道怎么学Python
  2. python工资一般多少p-为什么这么多人喜欢Python?Python的就业方向是什么?
  3. python学了有什么用-python学来有什么用
  4. python能做什么项目-python适合什么开发
  5. python和c 的区别-python和c语言的主要区别总结
  6. python入门经典100题-零基础学习Python开发练习100题实例(1)
  7. python-Python 函数
  8. python自动化办公教程百度云-693629 用Python自动办公,做职场高手(完结)
  9. 趋势网盘点:语音识别技术创新
  10. java语法格式整理