创建进程

在Linux系统

+ os.fork( ):创建子进程

(注意:fork( )函数只能用于Linux/Unix系统上,包括Mac)

fork被执行时,会将原来的程序复制一份副本作为子进程

子进程的fork会返回整数0 父进程的fork会返回自己的pid (父进程和子进程都是相互独立的两个程序)

  1. import os
  2. print("查询当前进程PID:", os.getppid())
  3. pid = os.fork() # 复制当前进程为子进程,并返回pid
  4. if pid == 0:
  5. print("(PID:", os.getppid(), ")", "正在运行子进程PID:", os.getppid())
  6. print("(PID:", os.getppid(), ")", "子进程的os.fork的返回值:", pid)
  7. print("(PID:", os.getppid(), ")", "父进程的PID:", os.getppid())
  8. else:
  9. print("(PID:", os.getppid(), ")", "正在运行父进程PID:", os.getppid())
  10. print("(PID:", os.getppid(), ")", "父进程的os.fork的返回值:", pid)
  1. #输出
  2. # 同时在运行的进程先后顺序是由系统控制的,一般认为是同步运行的即可
  3. #=======================================
  4. 查询当前进程PID 47734
  5. (PID: 47734 ) 正在运行父进程PID 47734
  6. (PID: 47734 ) 父进程的os.fork的返回值: 104322
  7. (PID: 104321 ) 正在运行子进程PID 104321
  8. (PID: 104321 ) 子进程的os.fork的返回值: 0
  9. (PID: 104321 ) 父进程的PID 104321

QQ截图202102171733491.png

+ os._exit( ):退出子进程

当os.fork( )创建的子进程完成任务后,由于种种原因可能不会直接被关闭, 这时这个没用的进程就会变成“僵尸进程”占用电脑资源。

必须使用os._exit( )方法,关闭子进程

  1. import os
  2. import sys
  3. pid = os.fork() # 复制当前进程为子进程,并返回pid
  4. p = os.getppid() # 返回目前进程的PID
  5. if pid == 0:
  6. print("(PID:", p, ")", end=" ")
  7. print("正在执行子进程")
  8. os._exit(0) # 退出子进程
  9. print("进程已被os._exit()退出,此处不会被执行")
  10. else:
  11. print("(PID:", p, ")", end=" ")
  12. print("当前执行的是父进程")
  13. print("运行结束")
  14. sys.exit(0) # 退出主进程
  1. #输出
  2. #=======================================
  3. (PID: 4934 ) 当前执行的是父进程
  4. 运行结束
  5. (PID: 11982 ) 正在执行子进程

在Windows系统

Windows平台下可以使用multiprocessing模块来实现多进程功能, (其他平台也是可以用这个模块,Linux下封装了os.fork方法,windows下模拟了os.fork方法)

multiprocessing 多进程模块

+ Process:进程类

Process类创建的对象,就是一个进程对象 通过process类方法,可以控制进程

Docs:https://docs.python.org/zh-cn/3/library/multiprocessing.html?highlight=exitcode#multiprocessing.Process

L- 多进程 - 图2```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()

  1. print("开始运行子进程")
  2. p.join()
  1. ```python
  2. # 输出
  3. #=================================
  4. 启动子进程
  5. 开始运行子进程
  6. Hibari
  7. New Proces PID: 27532

windows系统下必须有 if name==”name
QQ截图20210218034819.png

+ join( ):暂停主线程,等待子线程

如果调用了 join,主进程会等待子进程运行结束后才会接着往下运行 如果没有调用join,主进程和进程会同时一起运行

join( )适用于 Pool进程池类和Process进程类

  1. import os, time
  2. from multiprocessing import Process
  3. def func(s):
  4. print("当前是子进程")
  5. time.sleep(2)
  6. print("当前是子进程")
  7. return None
  8. if __name__ == "__main__":
  9. p = Process(target = func, args=('Hibari',))
  10. p.start()
  11. #p.join() # 不使用jion 主进程和子进程会同步运行
  12. print("当前是主进程")
  13. time.sleep(1)
  14. print("当前是主进程")
  15. # 输出
  16. # =============================================
  17. 当前是主进程
  18. 当前是子进程
  19. 当前是主进程
  20. 当前是子进程
  1. import os, time
  2. from multiprocessing import Process
  3. def func(s):
  4. print("当前是子进程")
  5. time.sleep(2)
  6. print("当前是子进程")
  7. return None
  8. if __name__ == "__main__":
  9. p = Process(target = func, args=('Hibari',))
  10. p.start()
  11. p.join() # 使用join暂停主进程后,开始运行子进程
  12. print("当前是主进程")
  13. time.sleep(1)
  14. print("当前是主进程")
  15. # 输出
  16. # =============================================
  17. 当前是子进程
  18. 当前是子进程
  19. 当前是主进程
  20. 当前是主进程

+ Pool:批量创建进程类(进程池)

Pool的功能基本和Process差不多, 但Pool可以一次性批量生成子进程,并统一管理 (即一个join、close等方法可以控制一批进程)

L- 多进程 - 图4```python from multiprocessing import Pool import os, time

def func(s): print(s,”:PID”,os.getpid()) time.sleep(1) #暂停程序1秒

if name == “main“:

  1. p = Pool(3)
  2. p.apply_async(func, args = ("A",))
  3. p.apply_async(func, args = ("B",))
  4. p.apply_async(func, args = ("C",))
  5. p.apply_async(func, args = ("D",))
  6. p.apply_async(func, args = ("E",))
  7. p.apply_async(func, args = ("F",))
  8. p.apply_async(func, args = ("G",))
  9. p.close() # 关闭进程池,不在接受新进程
  10. print("开始运行进程池")
  11. p.join() # 暂停主程序,开始运行进程池
  12. print("进程池结束")
  1. > 当我们运行程序时会发现,进程池会以每3个进程为一组,
  2. > 上一组运行结束后,才会运行下一组
  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)
  4. <a name="03MC1"></a>
  5. #### + Queue:进程通信类
  6. >
  7. > 每一个进程实际上都是一个独立的程序,一个进程并没有办法直接读取另一个进程的数据
  8. > Queue类提供了,进程与进程之间交换数据的可能
  9. >
  10. > **类方法:**
  11. > put( ) :输入
  12. > get( ) :获取
  13. >
  14. > **注意:**进程必须**同时****运行**才能读取或输出成功(假如输出的进程,在输出完后结束,另一个进程无法读取)
  15. > **注意:**必须控制好输出进程先输出,读取的后读取,否则会抛出异常
  16. > (读取时,最好加个try 配合while死循环,读取到再退出读取)
  17. ```python
  18. from multiprocessing import Process
  19. from multiprocessing import Queue
  20. def FunSend(x):
  21. while True:
  22. x.put("Hibari") # 输出【Queue对象的属性方法】
  23. def FunRead(x):
  24. Value = x.get(True) # 读取【Queue对象的属性方法】
  25. print("这时进程A,读取进程B的内容:",Value)
  26. if __name__ == "__main__":
  27. xi = Queue()
  28. A = Process(target=FunSend, args=(xi,)) # 定义输出进程
  29. B = Process(target=FunRead, args=(xi,)) # 定义读取进程
  30. A.start()
  31. #A.join()
  32. B.start()
  33. B.join()
  1. #输出
  2. #===============================
  3. 这时进程A,读取进程B的内容: Hibari

subprocess 子进程管理模块

这个模块,可以打开外部程序,并作为子进程进行管理 (要想使用好这个模块,需要对CMD、Shell、PowerShell这类命令比较熟悉)

————os模块—————

在开始之前,先来复习几个os方法

+ os.system( ):调用CMD或终端

os.system( command ): 方法运行我们去使用系统的CMD指令 当然也能运行程序

command:字符串 用于表示指令和参数,指令与参数之间用空格隔开即可

返回值:整数 当os.system 打开的程序被关闭时,会返回退出码, 正常是0,不正常是非0

  1. import os
  2. print("启动音乐应用")
  3. r = os.system(r'"D:\Program Files (x86)\Netease\CloudMusic\cloudmusic.exe"')
  4. print("程序终止,退出码:", r)

QQ录屏20210219210752.gif
如果我们用任务管理器直接关闭程序,此时退出码就是1了
QQ截图20210219212251.png

+ 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:返回程序退出码

  1. import os
  2. obj = os.popen("ping 114.114.114.114", 'r', 1)
  3. s=obj.read()
  4. #print(s)
  5. print("程序结束")

QQ截图20210219231546.png QQ截图20210219231603.png

———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】 如果你们有解决办法请告诉我,作为菜鸡的我表示谢谢

  1. import subprocess
  2. import os
  3. subprocess.call(r"D:\Administrator\Desktop\MyFile.py")

QQ截图20210219180758.png