一、如何获取进程的id号和进程的名字.
os.getpid() #获取本进程的id号
os.getppid() #获取本进程的父进程的id号
import os
from multiprocessing import Process
def f1():
print('f1进程的pid',os.getpid())
print('f1进程的父进程的pid',os.getppid())
if __name__ == '__main__':
p1 = Process(target=f1,name='欢迎')
p1.start()
print(p1.name)
print('p1进程的pid',p1.pid)
print('本进程的id',os.getpid())
# p1.pid #返回结果为p1进程的id号
# os.getpid()#返回本进程的id号
# os.getppid()#返回为本进程的父进程id号
# p1.name()#返回p1进程的名字
二、如何手动结束子进程,以及判断子进程是否还在运行
obj.is_terminate() #给操作系统发送结束进程的信号
obj.is_alive() #判断进程是否在运行,返回值True,False
import time
from multiprocessing import Process
def f1():
print('子进程1号')
if __name__ == '__main__':
p = Process(target=f1,)
p.start()
print(p.is_alive()) #判断子进程是否还活着,是否还在运行
p.terminate() #给操作系统发送一个结束进程的信号
time.sleep(0.5) #需要延迟一会再判断是否还存活,因为系统结束进程需要处理很多东西
print(p.is_alive())
三、如何验证进程存在空间隔离
对于打印结果的解释:首先程序自上往下走,先打印一遍100,开启子进程后,系统copy一份代码走,并运行,又打印一遍100,子进程修改的只是自己进程里的全局变量,
而父进程的变量还是那个,这就验证了进程之间存在空间隔离.
from multiprocessing import Process
num = 100
def f1():
global num
num = 3 #修改全局变量的值
print('f1进程中的num',num)
print('>>>>>',num)
if __name__ == '__main__':
p = Process(target=f1,)
p.start()
p.join()
print('主进程中的num',num)
打印结果为:
>>>>> 100
>>>>> 100
f1进程中的num 3
主进程中的num 100
四、关于守护进程
obj(进程的实例化对象).daemon = True #开启守护进程,一定要在开启进程( obj.start() )前设置
什么是守护进程:
1.在主进程代码执行结束后就终止(应用场景:子进程需要跟父进程一起结束时)
2.守护进程内无法开启子进程,否则抛异常
from multiprocessing import Process
def f1():
print("xxx")
def f2():
print("p普通子进车")
if __name__ == '__main__':
p = Process(target = f1,)
p.daemon = True #开启守护进程,一定要在开启该进程(p.start())前设置,父进程代码执行结束,这个守护进程也结束.
p.start()
#p.join() #给主进程阻塞,守护进程有机会执行里面的代码
print("主进程结束.")
p2 = Process(target = f2,) #普通进程不受限制
p2.start()
五、关于僵尸进程和孤儿进程概念
僵尸进程:在子进程执行完,而主进程还没有执行完的时候,系统会保留执行的子进程一些信息(id号,名字...),它会随着主进程的结束而被清理掉
孤儿进程:主进程在子进程前结束了,这个时候该子进程的一些信息没人管了,就叫孤儿进程,最后会被系统清理.
六、关于互斥锁\进程锁\同步锁:
什么时进程所\互斥锁\同步锁: 控制进程在共享一个文件,或同一个打印终端的时候,产生竞争时的错乱.原理是把并发改成串行
with obj(锁的实例化对象): #简易写法
需要上锁的代码
Lock.acquire() #加锁
Lock.release() #解锁
from multiprocessing import Process,Lock
import time
def show_t(i):
with open("ticket","r",encoding = "utf-8")as f: #用with open打开文件,前2个可以用位置参数,但第三个必须用关键字传参
ticket_data = f.read()
t_data = eval(ticket_data)
print("%s查询剩余票数为%s"%(i,t_data["count"]))
def get_t(i,l1):
# l1.acquire()#加锁
with l1: #用了该枷锁方法,就不用手动解锁了
with open("ticket","r",encoding="utf-8")as f:
ticket_data = f.read() #ticket票 data数据
t_data = eval(ticket_data)
if t_data["count"]>0:
t_data["count"]-=1
print("%s抢票成功"%i)
time.sleep(0.2)
with open("ticket","w")as f:
f.write(str(t_data))
else:
print("没有票了")
# l1.release() #解锁
if __name__ == '__main__':
l1 = Lock()
for i in range(10):
p1 = Process(target=show_t,args=(i,))
p1.start()
for i in range(10):
p2=Process(target=get_t,args=(i,l1)) #传两个参数要加括号
p2.start()
七、关于multiprocessing包的Queue模块的使用
方法介绍:
obj.put() #往队列里面放数据,如果队列里面满了,会阻塞
obj.put_nowait() #满了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作)
obj.get() #从队列里面取数据,如果队列里面空了,会阻塞(等待)
obj.get_nowait() #空了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作)
obj.full() #查看队列是否满了,满了返回True,但该命令的执行速度比put和get的速度快,所以结果不准确
obj.empty() #查看队列是否空了,空了返回True,结果同理,有时不准确
obj.qsize() #返回当前队列内容的长度,结果也不准确
举例:关于Queue
from multiprocessing import Process,Queue
def f1(q):
q.put('约吗?')
if __name__ == '__main__':
q = Queue(3)
p = Process(target=f1,args=(q,))
p.start() #开启子进程
son_p_msg = q.get() #从队列里面拿数据,队列为空,则阻塞等待
print('来自子进程的消息:',son_p_msg)
八、JoinableQueue方法(跟Queue相近)
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
方法介绍:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
下面例子中,应用此方法目的,是为了解决,当有多个消费者程序,去队列里拿数据的时候,不知道队列里是否空了,而此方法,会往队列里面放入一个信号,表示该数据被拿走了.
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
import time
from multiprocessing import Process,Queue,JoinableQueue
#生产者
def producer(q):
for i in range(10):
time.sleep(0.2)
s = '大包子%s号'%i
print(s+'新鲜出炉,拿去用')
q.put(s)
q.join() #等待的是队列的内容处理完毕(q是队列的实例化对象),而不是等待上面代码执行,就等着task_done()信号的数量,和我put进去的数量相同时,才继续执行下面代码
print('所有的任务都被处理了,继续潜行吧骚年们')
#消费者
def consumer(q):
while 1:
time.sleep(0.5)
baozi = q.get()
print(baozi+'被吃了')
q.task_done() #给队列发送一个取出的这个任务已经处理完毕的信号
if __name__ == '__main__':
# q = Queue(30)
q = JoinableQueue(30) #同样是一个长度为30的队列
pro_p = Process(target=producer,args=(q,))
con_p = Process(target=consumer,args=(q,))
pro_p.start()
con_p.daemon = True #开启守护进程,消费者会随着主进程的结束而终结
con_p.start()
pro_p.join() #让主进程等待(生产者)子进程
print('主进程结束')
九、Manager方法
什么是Manager方法:
Manager是是一种数据共享的方法.一种较为高级的多进程通信方式
进程之间的通信:队列、管道、数据共享(Manager).
队列,管道,这些方式只适用于多个进程都是源于同一个父进程的情况。如果多个进程不是源于同一个父进程,只能用共享内存,信号量等方式,还有就是数据共享(Manager)
多进程共同去处理共享数据的时候,就和我们多进程同时去操作一个文件中的数据是一样的,不加锁就会出现错误的结果,进程不安全的,所以也需要加锁
import time
from multiprocessing import Process,Manager,Lock #创建进程的方法\数据共享的方法\互斥锁方法
def f1(m_d,l2):
with l2:
tmp = m_d["num"]
tmp -= 1
time.sleep(0.1)
m_d["num"]=tmp
if __name__ == '__main__':
m = Manager() #实例化数据共享的对象
l2 = Lock #实例化锁的对象
m_d = m.dict({"num":100})
p_list = []
for i in range(10):
p = Process(target=f1,args=(m_d,l2))
p.start()
p_list.append(p)
[pp.join() for pp in p_list]
print(m_d["num"])