多进程操作
(一)sultiprocessing模块介绍
- python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。
- Python提供了multiprocessing。
- multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
- multiprocessing模块的功能众多:
- 支持子进程、通信和共享数据、执行不同形式的同步
- 提供了Process、Queue、Pipe、Lock等组件。
- 需要再次强调的一点是:
- 与线程不同,进程没有任何共享状
- 进程修改的数据,改动仅限于该进程内。
(二)Process类的介绍
(1)创建进程的类
- 语法
Process([group [, target [, name [, args [, kwargs]]]]])
- 由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
- 需要使用关键字的方式来指定参数
- args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
(2)参数介绍
- group参数未使用,值始终为None
- target表示调用对象,即子进程要执行的任务
- args表示调用对象的位置参数元组,args=(1,2,'ly',)
- kwargs表示调用对象的字典,kwargs=
- name为子进程的名称
(3)方法介绍
p.start()
:- 启动进程,并调用该子进程中的p.run()
p.run()
:- 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate()
:- 强制终止进程p,不会进行任何清理操作
- 如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。
- 如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive()
:- 如果p仍然运行,返回True
p.join([timeout])
:- 主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。
- timeout是可选的超时时间
- 需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
(4)属性介绍
p.daemon
:- 默认值为False
- 如果设为True,代表p为后台运行的守护进程
- 当p的父进程终止时,p也随之终止
- 并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name
:- 进程的名称
p.pid
:- 进程的pid
p.exitcode
:- 进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey
:- 进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。
- 这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
(三)Process类的使用
(1)特别提醒
- 注意::在windows中Process()必须放到 if name=='main':下
(2)创建并开启子进程的两种方式
(1)方法一:直接使用Process方法
"""直接使用Process的方法"""
# 导入模块
from multiprocessing import Process
def run(name):
print(f"名称:{name}")
# 使用Process方式实例化得到任务对象
if __name__ == '__main__':
# 创建进程对象
# Process(target=被调用的函数(任务名/进程名),args=(参数,))
# args 是以元组的形式 里面的参数一定要用逗号隔开,哪怕只有一个参数也要用逗号
p=Process(target=run,args=('syh',))
p1=Process(target=run,args=('su',))
p2=Process(target=run,args=('s',))
# p.start()开启进程
# 告诉操作系统帮我们创建一个进程
p.start()
p1.start()
p2.start()
# 一定是主进程先跑起来的,再去启动子进程
# 子进程的顺序是不确定的,由操作系统调度
# 名称:s
# 名称:syh
# 名称:su
(2)方法二:继承Process类
from multiprocessing import Process
"""继承Process类"""
# 创建一个新类继承Process
class myProcess(Process):
def __init__(self,name):
super().__init__()
self.name=name
# 定义一个任务函数
def run(self):
print(f"{self.name}正在运行!!")
if __name__ == '__main__':
# 创建子进程
p=myProcess(name='hhhh')
p1=myProcess(name='ssss')
p2=myProcess(name='yyyy')
# 启动主进程和子进程
# 告诉操作系统帮我们创建一个进程
p.start()
p1.start()
p2.start()
# hhhh正在运行!!
# ssss正在运行!!
# yyyy正在运行!!
- 创建进程就是在内存中申请一块内存空间将需要运行的代码丢进去
- 一个进程对应在内存中就是一块独立的空间
- 多个进程对应在内存中就是多块独立的内存空间
- 进程与进程之间数据默认情况下是无法直接交互的,如果想交互可以借助第三方工具或模块
(3)进程之间的内存空间是隔离的
- 每一个子进程之间的数据是相互隔离的
- 在执行子进程代码时,只修改自己子进程内的数据,不会影响到其他的子进程
# 正常函数修改全局变量
number=99
def text(i):
global number
number +=1
print(f"这是子进程{i}中的数据{number}")
def main():
text(i=1)
text(i=2)
text(i=3)
# 这是子进程1中的数据100
# 这是子进程2中的数据101
# 这是子进程3中的数据102
# 进程之间的修改全局变量是相互隔离的
import multiprocessing
number=99
def text(i):
global number # 局部修改全局变量
number +=1
print(f"这是子进程{i}中的数据{number}")
if __name__ == '__main__':
for i in range(1,6):
p=multiprocessing.Process(target=text,args=(i,))
p.start()
# 这是子进程2中的数据100
# 这是子进程1中的数据100
# 这是子进程5中的数据100
# 这是子进程3中的数据100
# 这是子进程4中的数据100
(4)socket通信变成并发的形式
-
多个客户端
-
client
# 导入模块
import socket
# 获取客户端对象
client=socket.socket()
# 建立客户端连接
client.connect(('127.0.0.1',9663))
while True:
send_msg=input("请输入小写字母:").strip()
if not send_msg:
continue
client.send(send_msg.encode('utf-8'))
# 接收反馈信息
msg=client.recv(1024)
print(msg.decode('utf-8'))
- server
# 导入模块
import socket
server=socket.socket()
from socket import *
import multiprocessing
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
# 获取服务端对象
# 建立服务端连接
server.bind(('127.0.0.1',9663))
# 指定半连接池大小
server.listen()
# 接收信息 和 反馈信息
def recv(conn,addr):
while True:
# 检查是否由异常,并处理异常
try:
msg=conn.recv(1024)
if not msg:
break
msg=msg.decode('utf-8')
print(msg)
print(addr)
# 反馈信息
send_msg=msg.upper()
conn.send(send_msg.encode('utf-8'))
except Exception as e:
break
def main():
while True:
# 接收客户端连接
conn,addr=server.accept()
# 创建进程对象
p=multiprocessing.Process(target=recv,args=(conn,addr))
# 启动进程
p.start()
if __name__ == '__main__':
main()
(5)Process对象的join方法
- 将并行改为串行
- join:主进程等待,等待子进程结束
(1)非join方法---并行
# 没有加入join方法的时候,处于并行状态,
# 将主进程启动起来后,并没有按照顺序拿到子进程的结果
# 导入模块
from multiprocessing import Process
import os
import time
def test(i):
print(f"这是进程{i} 子进程号{os.getpid()} 开始!!!")
# 模拟IO阻塞
time.sleep(2)
print(f"这是进程{i} 子进程号{os.getpid()} 结束!!!")
if __name__ == '__main__':
for i in range(1,4):
# 创建进程对象
p=Process(target=test,args=(i,))
# 启动进程对象
p.start()
"""
没有加入join方法的时候,处于并行状态,
将主进程启动起来后,并没有按照顺序拿到子进程的结果
"""
# 这是进程1 子进程号15148 开始!!!
# 这是进程2 子进程号14420 开始!!!
# 这是进程3 子进程号21896 开始!!!
# 这是进程2 子进程号14420 结束!!!
# 这是进程1 子进程号15148 结束!!!
# 这是进程3 子进程号21896 结束!!!
(2)jion方法---串行
# 加入join 方法的时候,处于串行的状态
# 将主进程启动后,按照串行的执行顺序依次执行子进程,拿到了子进程的结#果后再继续往后执行
# 主进程等待子进程结束后,再结束主进程
# 我先启动主进程
# 接着启动每一个子进程
# 主进程等待所有子进程结束后再结束子进程
# 导入模块
from multiprocessing import Process
import os
import time
def test(i):
print(f"这是进程{i} 子进程号{os.getpid()} 开始!!!")
# 模拟IO阻塞
time.sleep(2)
print(f"这是进程{i} 子进程号{os.getpid()} 结束!!!")
if __name__ == '__main__':
print("开始主进程")
for i in range(1,4):
# 创建进程对象
p=Process(target=test,args=(i,))
# 启动进程对象
p.start()
p.join()
print("结束主进程")
"""
加入join 方法的时候,处于串行的状态
将主进程启动后,按照串行的执行顺序依次执行子进程,拿到了子进程的结果后再继续往后执行
主进程等待子进程结束后,再结束主进程
"""
# 开始主进程
# 这是进程1 子进程号2228 开始!!!
# 这是进程1 子进程号2228 结束!!!
# 这是进程2 子进程号4704 开始!!!
# 这是进程2 子进程号4704 结束!!!
# 这是进程3 子进程号13652 开始!!!
# 这是进程3 子进程号13652 结束!!!
# 结束主进程
(3)join方法---并行
# join方法 实现并行的步骤
# 创建一个空的进程对象列表
# 创建进程对象
# 启动进程对象
# 将进程对象添加进进程列表中
# 遍历每个子进程
# 再用join()启动每个子进程
# 导入模块
from multiprocessing import Process
import os
import time
def test(i):
print(f"这是进程{i} 子进程号{os.getpid()} 开始!!!")
# 模拟IO阻塞
time.sleep(2)
print(f"这是进程{i} 子进程号{os.getpid()} 结束!!!")
if __name__ == '__main__':
print('进程开始')
start_time=time.time()
# 创建一个进程的空列表
p_list=[]
for i in range(1,4):
# 创建进程对象
p=Process(target=test,args=(i,))
# 启动进程对象
p.start()
# 将启动后的子进程扔进进程列表中
p_list.append(p)
# 逐个遍历每一个子进程
for p in p_list:
# 启动子进程
p.join()
print('进程结束')
print(f'总的耗时:{time.time()-start_time}')
# 进程开始
# 这是进程1 子进程号2600 开始!!!
# 这是进程2 子进程号2228 开始!!!
# 这是进程3 子进程号1524 开始!!!
# 这是进程1 子进程号2600 结束!!!
# 这是进程2 子进程号2228 结束!!!
# 这是进程3 子进程号1524 结束!!!
# 进程结束
# 总的耗时:2.1254165172576904
多进程开设模板
"""多进程开设模板"""
import os
import time
# 1.导入模块
from multiprocessing import Process
# 2.定义一个存在IO阻塞的进程
def test(i):
print(f"子进程{i}---开始---进程号为{os.getpid()}")
time.sleep(3)
print(f"子进程{i}---结束---进程号为{os.getpid()}")
# 3.开始多进程
def main():
# 定义一个空的进程列表
p_list=[]
for i in range(1,6):
# 创建进程对象
p=Process(target=test,args=(i,))
# 启动进程对象
p.start()
# 将进程对象添加进进程列表中
p_list.append(p)
# 遍历进程列表中的每一个子进程
for p in p_list:
# 主线程处于等的状态,子进程运行
p.join()
# 4.开启多进程
if __name__ == '__main__':
main()
(四)Process对象的其他方法或属性
(1)查看当前进程的进程号
(1)查看当前进程的进程号
(1)什么是进程号
- 一个计算机上面运行着很多的进程,那么计算机是如何区分并管理这些进程服务端呢?
- 计算机会给每一个运行的进程分配一个PID号
(2)如何查看进程号?
- windows系统
- CMD命令行 tasklist 查看
- Mac系统
- 终端运行 ps aux 查看
(3)如何根据指定进程号查看进程
- Mac系统
- 终端运行
ps aux|grep PID
即可查看
- 终端运行
- Windows系统
- CMD 命令行
tasklist |findstr PID
即可查看
- CMD 命令行
(2)查看当前进程的进程号方法
- current_process().pid 方法 查看当前的进程号
# current_process().pid 方法
# 导入模块
from multiprocessing import Process,current_process
import time
def test(i):
print(f"当前子进程{i}---进程号{current_process().pid}")
time.sleep(3)
if __name__ == '__main__':
print(f"这是当前进程的进程号{current_process().pid}")
for i in range(1,3):
p=Process(target=test,args=(i,))
p.start()
# 这是当前进程的进程号17648
# 当前子进程2---进程号14660
# 当前子进程1---进程号11336
(3)查看当前进程的进程号
- os.getpid() 方法 查看当前的进程号
# 导入模块
from multiprocessing import Process
import time
import os
def test(i):
print(f"当前子进程{i}---进程号{os.getpid()}")
time.sleep(3)
if __name__ == '__main__':
print(f"这是当前进程的进程号{os.getpid()}")
for i in range(1,3):
p=Process(target=test,args=(i,))
p.start()
# 这是当前进程的进程号21752
# 当前子进程1---进程号14652
# 当前子进程2---进程号22784
(4)查看当前进程的父进程号
- os.getppid() 方法 查看当前的父进程号
# 导入模块
from multiprocessing import Process
import time
import os
def test():
print(f"当前子进程的进程号{os.getpid()}")
print(f"这是当前子进程的父进程号{os.getppid()}")
time.sleep(3)
if __name__ == '__main__':
print("开始")
print(f"这是当前进程的进程号{os.getpid()}")
print(f"这是当前进程的父进程号{os.getppid()}")
p=Process(target=test)
p.start()
# 开始
# 这是当前进程的进程号1184
# 这是当前进程的父进程号22768
# 当前子进程的进程号13880
# 这是当前子进程的父进程号1184
(2)杀死当前进程
- p.terminate() 方法 杀死当前的进程
# 导入模块
from multiprocessing import Process
import time
# 定义一个IO进程
def test(i):
print(f"这是子进程{i}")
time.sleep(3)
if __name__ == '__main__':
for i in range(1,4):
p=Process(target=test,args=(i,))
p.start()
# 定义杀死进程的条件
if i == 2 :
# 符合条件的话, 就杀死进程
p.terminate()
# 这是子进程1
# 这是子进程3
(3)判断当前进程是否存活
- p.is_alive() 方法 判断当前的进程是否存活
# ######杀死当前的进程
# 导入模块
from multiprocessing import Process
import time
# 定义一个IO进程
def test():
print(f"这是当前子进程的进程号{os.getpid()}")
time.sleep(3)
if __name__ == '__main__':
p=Process(target=test)
p.start()
# 杀死当前的进程 需要给操作系统一点时间!!!
p.terminate()
time.sleep(2)
# 判断进程是否存活
# 子程序被杀死!!!
print(p.is_alive())
# False
print(f"主进程的进程号{os.getpid()}")
# 当前被杀死的是主进程的子进程
# 主进程正常
# False
# 主进程的进程号21192
- 一般默认会将
- 存储布尔值的变量名
- 返回的结果是布尔值的方法名
- 起成
is_
开头的变量名
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY