创建进程
在Linux系统
+ os.fork( ):创建子进程
(注意:fork( )函数只能用于Linux/Unix系统上,包括Mac)
fork被执行时,会将原来的程序复制一份副本作为子进程
子进程的fork会返回整数0 父进程的fork会返回自己的pid (父进程和子进程都是相互独立的两个程序)
import os
print("查询当前进程PID:", os.getppid())
pid = os.fork() # 复制当前进程为子进程,并返回pid
if pid == 0:
print("(PID:", os.getppid(), ")", "正在运行子进程PID:", os.getppid())
print("(PID:", os.getppid(), ")", "子进程的os.fork的返回值:", pid)
print("(PID:", os.getppid(), ")", "父进程的PID:", os.getppid())
else:
print("(PID:", os.getppid(), ")", "正在运行父进程PID:", os.getppid())
print("(PID:", os.getppid(), ")", "父进程的os.fork的返回值:", pid)
#输出
# 同时在运行的进程先后顺序是由系统控制的,一般认为是同步运行的即可
#=======================================
查询当前进程PID: 47734
(PID: 47734 ) 正在运行父进程PID: 47734
(PID: 47734 ) 父进程的os.fork的返回值: 104322
(PID: 104321 ) 正在运行子进程PID: 104321
(PID: 104321 ) 子进程的os.fork的返回值: 0
(PID: 104321 ) 父进程的PID: 104321
+ os._exit( ):退出子进程
当os.fork( )创建的子进程完成任务后,由于种种原因可能不会直接被关闭, 这时这个没用的进程就会变成“僵尸进程”占用电脑资源。
必须使用os._exit( )方法,关闭子进程
import os
import sys
pid = os.fork() # 复制当前进程为子进程,并返回pid
p = os.getppid() # 返回目前进程的PID
if pid == 0:
print("(PID:", p, ")", end=" ")
print("正在执行子进程")
os._exit(0) # 退出子进程
print("进程已被os._exit()退出,此处不会被执行")
else:
print("(PID:", p, ")", end=" ")
print("当前执行的是父进程")
print("运行结束")
sys.exit(0) # 退出主进程
#输出
#=======================================
(PID: 4934 ) 当前执行的是父进程
运行结束
(PID: 11982 ) 正在执行子进程
在Windows系统
Windows平台下可以使用multiprocessing模块来实现多进程功能, (其他平台也是可以用这个模块,Linux下封装了os.fork方法,windows下模拟了os.fork方法)
multiprocessing 多进程模块
+ Process:进程类
Process类创建的对象,就是一个进程对象 通过process类方法,可以控制进程
```python from multiprocessing import Process import os
def func(s): print(s) print(“New Proces PID:”, os.getpid()) return None
if name == “main“: p = Process(target = func, args=(‘Hibari’,)) print(“启动子进程”) p.start()
print("开始运行子进程")
p.join()
```python
# 输出
#=================================
启动子进程
开始运行子进程
Hibari
New Proces PID: 27532
windows系统下必须有 if name==”name“
+ join( ):暂停主线程,等待子线程
如果调用了 join,主进程会等待子进程运行结束后才会接着往下运行 如果没有调用join,主进程和进程会同时一起运行
join( )适用于 Pool进程池类和Process进程类
import os, time
from multiprocessing import Process
def func(s):
print("当前是子进程")
time.sleep(2)
print("当前是子进程")
return None
if __name__ == "__main__":
p = Process(target = func, args=('Hibari',))
p.start()
#p.join() # 不使用jion 主进程和子进程会同步运行
print("当前是主进程")
time.sleep(1)
print("当前是主进程")
# 输出
# =============================================
当前是主进程
当前是子进程
当前是主进程
当前是子进程
import os, time
from multiprocessing import Process
def func(s):
print("当前是子进程")
time.sleep(2)
print("当前是子进程")
return None
if __name__ == "__main__":
p = Process(target = func, args=('Hibari',))
p.start()
p.join() # 使用join暂停主进程后,开始运行子进程
print("当前是主进程")
time.sleep(1)
print("当前是主进程")
# 输出
# =============================================
当前是子进程
当前是子进程
当前是主进程
当前是主进程
+ Pool:批量创建进程类(进程池)
Pool的功能基本和Process差不多, 但Pool可以一次性批量生成子进程,并统一管理 (即一个join、close等方法可以控制一批进程)
```python from multiprocessing import Pool import os, time
def func(s): print(s,”:PID”,os.getpid()) time.sleep(1) #暂停程序1秒
if name == “main“:
p = Pool(3)
p.apply_async(func, args = ("A",))
p.apply_async(func, args = ("B",))
p.apply_async(func, args = ("C",))
p.apply_async(func, args = ("D",))
p.apply_async(func, args = ("E",))
p.apply_async(func, args = ("F",))
p.apply_async(func, args = ("G",))
p.close() # 关闭进程池,不在接受新进程
print("开始运行进程池")
p.join() # 暂停主程序,开始运行进程池
print("进程池结束")
> 当我们运行程序时会发现,进程池会以每3个进程为一组,
> 上一组运行结束后,才会运行下一组
![QQ录屏20210218214243.gif](https://cdn.nlark.com/yuque/0/2021/gif/2485877/1613655941732-dc1f6ac9-058d-4902-9a8e-43078f91d924.gif#align=left&display=inline&height=746&margin=%5Bobject%20Object%5D&name=QQ%E5%BD%95%E5%B1%8F20210218214243.gif&originHeight=746&originWidth=1106&size=3433689&status=done&style=none&width=1106)
<a name="03MC1"></a>
#### + Queue:进程通信类
>
> 每一个进程实际上都是一个独立的程序,一个进程并没有办法直接读取另一个进程的数据
> Queue类提供了,进程与进程之间交换数据的可能
>
> **类方法:**
> put( ) :输入
> get( ) :获取
>
> **注意:**进程必须**同时****运行**才能读取或输出成功(假如输出的进程,在输出完后结束,另一个进程无法读取)
> **注意:**必须控制好输出进程先输出,读取的后读取,否则会抛出异常
> (读取时,最好加个try 配合while死循环,读取到再退出读取)
```python
from multiprocessing import Process
from multiprocessing import Queue
def FunSend(x):
while True:
x.put("Hibari") # 输出【Queue对象的属性方法】
def FunRead(x):
Value = x.get(True) # 读取【Queue对象的属性方法】
print("这时进程A,读取进程B的内容:",Value)
if __name__ == "__main__":
xi = Queue()
A = Process(target=FunSend, args=(xi,)) # 定义输出进程
B = Process(target=FunRead, args=(xi,)) # 定义读取进程
A.start()
#A.join()
B.start()
B.join()
#输出
#===============================
这时进程A,读取进程B的内容: Hibari
subprocess 子进程管理模块
这个模块,可以打开外部程序,并作为子进程进行管理 (要想使用好这个模块,需要对CMD、Shell、PowerShell这类命令比较熟悉)
————os模块—————
在开始之前,先来复习几个os方法
+ os.system( ):调用CMD或终端
os.system( command ): 方法运行我们去使用系统的CMD指令 当然也能运行程序
command:字符串 用于表示指令和参数,指令与参数之间用空格隔开即可
返回值:整数 当os.system 打开的程序被关闭时,会返回退出码, 正常是0,不正常是非0
import os
print("启动音乐应用")
r = os.system(r'"D:\Program Files (x86)\Netease\CloudMusic\cloudmusic.exe"')
print("程序终止,退出码:", r)
如果我们用任务管理器直接关闭程序,此时退出码就是1了
+ os.popen( ):调用CMD或终端
os.popen的功能基本和os.system 但不会返回状态码(也不会输出到屏幕) 他会将信息输出到 缓冲池(文件) 里
方法原型:os.popen(cmd, mode=’r’, buffering=-1) 参数: command:和os.system一样,是指令 mode: 权限模式—-‘r’【表示对象读模式-默认】’w’【表示对象写模式】 buffering: 文件需要的缓冲大小 【0无缓冲;1行缓冲;负值为系统默认;其他值表示缓冲大小】 【一般默认值即可(默认值-1)】 返回值: 返回值是一个对象【os.popen是一个类,os.popen( )也创建了一个对象】 popen( )方法及属性:
read( ):读取缓冲池(文件) write( ):写入缓冲池 returncode:返回程序退出码
import os
obj = os.popen("ping 114.114.114.114", 'r', 1)
s=obj.read()
#print(s)
print("程序结束")
———subprocess模块———
这块内容,暂时保留,以后用到了再回来补充,浪费太多时间了,啃不动了 (大致的功能就是,创建一个子进程,用于运行外部程序) 要想学好这个模块,需要对计算机系统有一定的知识基础
+ subprocess 子进程
+ popen类
[?] 我的问题:OSError: [WinError 193] %1
当我尝试用 subprocess.call去调用一个 .py文件,但这个 .py文件无论如何都会抛出 【OSError: [WinError 193] %1 不是有效的 Win32 应用程序。】异常信息 但exe文件却不会有这个问题
我尝试将Python换成32位, 装32位的Anaconda3切换环境 删除Scripts都没有办法解决 【放弃了,不折腾了,反正用不着】
后来听说Linux上不会触发这个问题,但我没试过了, 【如果真的是想做一些比较大的项目,又对windows没有太大的需求,还是建议使用Linux】 如果你们有解决办法请告诉我,作为菜鸡的我表示谢谢
import subprocess
import os
subprocess.call(r"D:\Administrator\Desktop\MyFile.py")