洗礼灵魂,修炼python(89)-- 知识拾遗篇 —— 进程
进程
1.含义:计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。说白了就是一个程序的执行实例。
执行一个程序就是一个进程,比如你打开浏览器看到我的博客,浏览器本身是一个软件程序,你此时打开的浏览器就是一个进程。
2.进程的特性
-
一个进程里可以有多个子进程
-
新的进程的创建是完全拷贝整个主进程
-
进程里可以包含线程
-
进程之间(包括主进程和子进程)不存在数据共享,相互通信(浏览器和python之间的数据不能互通的),要通信则要借助队列,管道之类的
3.进程和线程之间的区别
-
线程共享地址空间,而进程之间有相互独立的空间
-
线程之间数据互通,相互操作,而进程不可以
-
新的线程比新的进程创建简单,比开进程的开销小很多
-
主线程可以影响子线程,而主进程不能影响子进程
4.在python中,进程与线程的用法就只是名字不同,使用的方法也是没多大区别
5.简单实例
1)创建一个简单的多进程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing,time def func(name): time.sleep( 1 ) print ( 'hello' ,name,time.ctime()) ml = [] for i in range ( 3 ): p = multiprocessing.Process(target = func,args = ( 'yang' ,)) p.start() ml.append(p) for i in ml: i.join() #注意这里,进程必须加join方法,不然会导致僵尸进程 |
运行结果:
不管怎么说,反正报错了,同样的代码,在python自带的IDLE里试试:
没有任何东西就结束了。好的,这里要说下了,按照我个人的理解,当你用pycharm或者IDLE时,pycharm或者IDLE在你的电脑里本身也是一个进程,并且默认是主进程。所以在pycharm会报错,而在IDLE里运行就是空白,个人理解,对不对暂且不谈,后期学到子进程时再说。
解决办法就是,其他的不变,加一个if __name == '__main__'判断就行:
这样就解决了,好的,你现在可以体会到那句话了,进程与线程的用法就只是名字不同,使用的方法也是没多大区别。不多说,自行体会。而运行结果看到的时间是同步的,那么这进程才是真正意义上的并行运行。
2)自定义类式进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing,time class myprocess(multiprocessing.Process): def __init__( self ,name): super (myprocess, self ).__init__() self .name = name def run( self ): time.sleep( 1 ) print ( 'hello' , self .name,time.ctime()) if __name__ = = '__main__' : ml = [] for i in range ( 3 ): p = myprocess( 'yang' ) p.start() ml.append(p) for j in ml: j.join() |
运行结果:
然后setDaemon之类的方法和线程也是完全一致的。
3)每一个进程都有根进程,换句话,每一个进程都有父进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing,time,os def info(): print ( 'mudule name:' ,__name__) print ( 'parent process:' ,os.getppid()) #父进程号 print ( 'son process:' ,os.getpid()) #子进程号 if __name__ = = '__main__' : info() print ( '-----' ) p = multiprocessing.Process(target = info,args = []) p.start() p.join() |
运行结果:
而查看我本机的进程:
可以知道,6204就是pycharm,正是此时的根进程,而主进程就是我这个py文件(由__main__可知),接着再往下的子进程等等等的。
6.多进程间的通信和数据共享
首先我们都已经知道进程之间是独立的,不可以互通,并且数据相互独立,而在实际开发中,一定会遇到需要进程间通信的场景要求,那么我们怎么搞呢
有两种方法:
- pipe
- queue
1)使用queue通信
在多线程那里已经学过queue了,创建queue的方式,q = queue.Queue(),这种创建是创建的线程queue,并不是进程queue。创建进程queue的方式是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing def func(q,name,age): #这里必须要把q对象作为参数传入才能实现进程之间通信 q.put({ 'name' :name, 'age' :age}) if __name__ = = '__main__' : q = multiprocessing.Queue() #创建进程queue对象 ml = [] for i in range ( 3 ): p = multiprocessing.Process(target = func,args = (q, 'yang' , 21 )) p.start() ml.append(p) print (q.get()) #获取queue信息 print (q.get()) print (q.get()) for i in ml: i.join() |
运行结果:
好的,已经通过queue实现通信,那么细心的朋友可能会想,此时的queue到底是同一个呢还是copy的呢?开始测试,码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing def func(q,name,age): q.put({ 'name' :name, 'age' :age}) print ( 'id:' , id (q)) if __name__ = = '__main__' : q = multiprocessing.Queue() ml = [] print ( 'id:' , id (q)) for i in range ( 3 ): p = multiprocessing.Process(target = func,args = (q, 'yang' , 21 )) p.start() ml.append(p) print (q.get()) print (q.get()) print (q.get()) for i in ml: i.join() |
在Windows平台运行结果:
Linux的ubuntu下是这样的:
这就不好怎么说了,我个人的理解,线程和进程这类与电脑硬件(CPU,RAM)等有联系的都有不确定因素,姑且认为在Windows平台里queue是copy的,在Linux里是同一个吧,并且据经验人士表示,在macbook上也是同一个。
还有个问题, 假如使用的queue是线程式的呢?
代码其他都没变,只改了这里:
结果:
虽然报错了,但是却有一个关键点,提示的是不能pickle线程锁对象,也就是说刚才我们使用的queue是进程对象,所以可以pickle,注意了,这里就是关键点,使用了pickle,那么也就是说,在Windows平台里是copy的,如果不是copy,就不需要存在pickle对吧?直接拿来用就是啊,干嘛要pickle之后取的时候再反pickle呢对吧?
再看Linux下呢,由于Linux默认是python2,所以模块包名稍微有点不同
结果阻塞住了,但是前面的还是出来了,看到的id果然还是一样的。
这里就有三点需要注意:(个人理解,如有误望指正)
1.进程里的确不能使用线程式queue
2.Windows平台的进程式queue是copy的
3.Linux平台的线程式和进程式都是同一个,但是如果在进程里使用线程式queue会阻塞住
但我个人觉得copy更有安全性
2)使用pipe通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing def func(conn): conn.send( '约吗?' ) #子进程发送数据 print (conn.recv()) #接受数据,不能加参数1024之类的 conn.close() #子进程关闭连接 if __name__ = = '__main__' : parent_conn,son_conn = multiprocessing.Pipe() #创建pipe对象,父进程,子进程 ml = [] p = multiprocessing.Process(target = func,args = (son_conn,)) p.start() print (parent_conn.recv()) #父进程接受数据,不能加参数1024之类的 parent_conn.send( '不约' ) #发送数据 p.join() #join方法是进程特有 |
运行结果:
这样就联系上了,相信你发现了,基本和前面的socket差不多,不过唯一的不同是recv()方法不能加参数,不信的话,你加来试试
反观线程通信,相信你会觉得进程比线程更方便
当然pipe也可以有多个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing,time def func(conn): conn.send( '约吗?' ) #子进程发送数据 print (conn.recv()) conn.close() #子进程关闭连接 if __name__ = = '__main__' : parent_conn,son_conn = multiprocessing.Pipe() #创建pipe对象,父进程,子进程 ml = [] for i in range ( 3 ): p = multiprocessing.Process(target = func,args = (son_conn,)) p.start() ml.append(p) print (parent_conn.recv()) #父进程接受数据,不能加参数1024之类的 parent_conn.send( '不约' ) for i in ml: i.join() |
运行结果:
7.进程之间数据共享——manager
比较简单,就利用了进程里的manager对象下的各个数据类型,其他的很简单的,我就不注释了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva import multiprocessing def func(l,d,num): l.append(num) d[num] = num if __name__ = = '__main__' : with multiprocessing.Manager() as manager: l = manager. list () d = manager. dict () ml = [] for i in range ( 6 ): p = multiprocessing.Process(target = func,args = (l,d,i)) p.start() ml.append(p) for i in ml: i.join() print ( 'd:' ,d) print ( 'l:' ,l) |
运行结果:
这样是不是就实现了数据共享了?
好的,进程也解析完了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】