
如何在代码中查看当前进程的PID呢?又如何在python代码中开启进程呢?可以借助multiprocessing模块。
import time
import os
from multiprocessing import Process, current_process
'''
current_process().pid可以获取当前进程的进程号PID
os.getpid()也可以获取当前进程的进程号PID
'''
# 子进程的任务
def func(name):
print(f'{name} start')
time.sleep(2)
print(f'func {current_process().pid},current——process获取进程号')
print(f'func {os.getpid()},OS获取进程号')
print(f'{name} end')
if __name__ == '__main__':
# 创建子进程,target是子进程需要执行的任务,args是任务的参数,为元组形式
p = Process(target=func, args=('zhuang', ))
# 开启子进程
p.start()
# 执行当前文件就是主进程
print(f'current_process获取进程号{current_process().pid},主进程结束')
print(f'os获取进程号{os.getpid()},主进程结束')
# 代码运行结果
current_process获取进程号2868,主进程结束
os获取进程号2868,主进程结束
zhuang start
func 26520,current——process获取进程号
func 26520,OS获取进程号
zhuang end
方式二:继承Process类,重写父类的run方法
import time
import os
from multiprocessing import Process, current_process
# 子进程的任务
def func(name):
print(f'{name} start')
time.sleep(2)
print(f'func {current_process().pid},current——process获取进程号')
print(f'func {os.getpid()},OS获取进程号')
print(f'{name} end')
class MyProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self): # start会自动调用run
func(self.name)
if __name__ == '__main__':
p = MyProcess('zhuang')
p.start() # p.run()只有通过start开启的才是子进程,通过run开启的不是子进程
print('主进程结束')
通过上述代码的执行结果,我们可以发现,主进程并没有等子进程执行完毕,这就是一个异步的操作。我们可以同时开多个子进程:
from multiprocessing import Process
def func(name):
print(f'{name} is start')
time.sleep(2)
print(f'{name} is done')
if __name__ == '__main__':
for i in range(1, 4):
p = Process(target=func, args=(f'p{i}', i))
p.start()
print('主进程结束')
# 输出:
主进程结束
p3 is start
p1 is start
p2 is start
p1 is done
p2 is done
p3 is done
同时开启三个子进程,打印的顺序也就是执行顺序是变化的,子进程通过start开启,本质是应用程序向操作系统发起请求,让操作系统开子进程。这是一个异步的操作,操作系统接到任务后,会根据整体情况做统筹安排,所以每个子进程开启的时间不按顺序,结束的时间也不按顺序。并且主进程并没有等待子进程结束才运行。
import time
import os
from multiprocessing import Process
# 子进程的任务
def func(name):
print(f'{name} is start')
time.sleep(2)
print(f'{name} is end')
if __name__ == '__main__':
# 创建子进程,target是子进程需要执行的任务,args是任务的参数,为元组形式
p = Process(target=func, args=('zhuang', ))
# 开启子进程
p.start()
# 等待子进程结束才往下运行
p.join()
# 执行当前文件就是主进程
print(f'os获取进程号{os.getpid()},主进程结束')
# 运行结果如下
zhuang start
zhuang end
os获取进程号15816,主进程结束
主进程等待子进程的过程也分为两种情况:
第一种:先开启所有子进程再让主进程等待
当主进程等待子进程的时候,卡住的是主进程。此时所有的子进程已经交给操作系统开启了,子进程会正常运行的,等所有的子进程运行结束,主进程再运行。此时每个子进程是并发运行的,因此主进程等待的时间是子进程所需运行时间最长的3s左右,如下代码
import time
import os
from multiprocessing import Process
# 子进程的任务
def func(name, i):
print(f'{name} start')
time.sleep(i)
print(f'{name} end')
if __name__ == '__main__':
p_list = []
for i in range(1, 4):
p = Process(target=func, args=(f'p{i}', i))
p_list.append(p)
p.start() # 先开启所有子进程
for p in p_list:
p.join() # 再让主进程等待子进程
print('主进程结束')
# 运行结果如下
p2 is start
p1 is start
p3 is start
p1 is done
p2 is done
p3 is done
主进程结束
第二种,每个子进程开启后都需要执行完成后才能往下执行
这种情况程序的运行就会变成串行,每个进程都需要等上个进程执行完毕才能执行。如下代码
import time
import os
from multiprocessing import Process
# 子进程的任务
def func(name, i):
print(f'{name} start')
time.sleep(i)
print(f'{name} end')
if __name__ == '__main__':
for i in range(1, 4):
p = Process(target=func, args=(f'p{i}', i))
p.start() # 先开启所有子进程
p.join() # 一个一个运行子进程
print('主进程结束')
# 运行结果,变成了串行
p1 is start
p1 is done
p2 is start
p2 is done
p3 is start
p3 is done
主进程结束
money = 100
def task():
global money
money = 666
print('子', money) # 666
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join() # 主进程等待子进程p结束后再执行
print('主', money) # 100
from multiprocessing import Process, current_process
import os
# 进程对象的数据属性和函数属性
p.start() # 开启子进程
p.join() # 主进程等待p进程结束
p.run() # p进程具体执行的任务,可以重写这个方法
p.is_alive() # 判断子进程是否存活,返回布尔值
p.terminate() # 结束子进程, 异步调用操作系统,所以不会立马关闭
p.kill() # 结束子进程,同理
p.name # 获取子进程的名字或修改之,注意自定义类时name属性的命名冲突问题,先super再赋值
p.daemon # 判断子进程是否为守护进程,或者设置其为守护进程,p.daemon = True
# 补充:获取进程的pid
current_process().pid # 当前进程pid
os.getpid() # 当前进程pid
os.getppid() # 当前进程的父进程的pid
from multiprocessing import Process
import time
def task(name):
print(f'{name}娘娘开始侍候皇帝')
time.sleep(3)
print(f'{name}已经正常死亡')
if __name__ == '__main__':
p = Process(target=task, kwargs={'name':'王后'})
# 这句话一定要放在start上面,否则会报错
p.daemon = True # 将进程p设置成守护进程
p.start()
# time.sleep(5) # 加上这句代码守护进程就会正常结束
print('秦始皇寿终正寝!')
from multiprocessing import Lock
mutex = Lock()
mutex.acquire() # 抢锁
mutex.release() # 释放锁,还锁
我们以抢票为例,说明如何使用锁:
from multiprocessing import Process, Lock
import json
import random
import time
class People:
def __init__(self,name):
self.name = name
# 查询余票
def query(self):
with open('data','r',encoding='utf-8') as f:
dic = json.load(f)
num = dic.get('ticket_num')
print(f'{self.name} 查询到余票是{num}')
return dic
# 购买票
def buy(self):
dic = self.query()
time.sleep(random.randint(1,3))
if dic.get('ticket_num') > 0:
dic['ticket_num'] -= 1
with open('data','w',encoding='utf-8') as f:
json.dump(dic,f)
print(f'{self.name}订票成功')
else:
print(f'{self.name}订票失败')
# 整合上面两个方法
def run(self, mutex):
# 先查余票
self.query()
# 子进程进行抢锁
mutex.acquire()
self.buy()
# 购票操作完成后释放锁,由其他子进程继续争抢
mutex.release()
if __name__ == '__main__':
mutex = Lock() # 获取锁
for i in range(10):
p = Process(target=People(i).run,args=(mutex,))
p.start()
假设在字典中存的票数为1张,如果同时有10个子进程查询每个进程都会查到1张票,那么这10个子进程就会同时去买票,如果不加锁的话出现的情况就是每个人都买到了,显然在逻辑上是错误的,但是加锁后就可以避免这个问题的发生。
锁不要轻易使用,只在多个进程争抢数据的环节进行加锁即可。
from multiprocessing import Queue
# 创建一个队列
q = Queue(5) # 括号内可以传数字 标示生成的队列最大可以同时存放的数据量
q.put(111)
q.put(222)
q.put(333)
# print(q.full()) # 判断当前队列是否满了
# print(q.empty()) # 判断当前队列是否空了
q.put(444)
q.put(555)
# print(q.full()) # 判断当前队列是否满了
# q.put(666) # 当队列数据放满了之后 如果还有数据要放程序会阻塞 直到有位置让出来 不会报错
"""
存取数据 存是为了更好的取
千方百计的存、简单快捷的取
"""
# 去队列中取数据
v1 = q.get()
v2 = q.get()
v3 = q.get()
v4 = q.get()
v5 = q.get()
# print(q.empty())
# V6 = q.get_nowait() # 没有数据直接报错queue.Empty
# v6 = q.get(timeout=3) # 没有数据之后原地等待三秒之后再报错 queue.Empty
try:
v6 = q.get(timeout=3)
print(v6)
except Exception as e:
print('一滴都没有了!')
# # v6 = q.get() # 队列中如果已经没有数据的话 get方法会原地阻塞
# print(v1, v2, v3, v4, v5, v6)
"""
q.full()
q.empty()
q.get_nowait()
在多进程的情况下是不精确
"""
from multiprocessing import Queue, Process
def producer(q):
q.put('hello, 很高兴为您服务')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
q.put('start') # 主进程传数据
转载请注明:XAMPP中文组官网 » Python并发编程之进程操作案例