Python并发编程—fork的使用
基于fork的多进程编程
fork使用
pid = os.fork()
功能: 创建新的进程
返回值:整数,如果创建进程失败返回一个负数,如果成功则在原有进程中返回新进程的PID,在新进程中返回0
注意:
- 子进程会复制父进程全部内存空间,从fork下一句开始执行。
- 父子进程各自独立运行,运行顺序不一定。
- 利用父子进程fork返回值的区别,配合if结构让父子进程执行不同的内容几乎是固定搭配。
- 父子进程有各自特有特征比如PID PCB 命令集等。
- 父进程fork之前开辟的空间子进程同样拥有,父子进程对各自空间的操作不会相互影响。
1 import os 2 from time import sleep 3 4 pid = os.fork() 5 6 if pid < 0: 7 print("Create process failed") 8 elif pid == 0: 9 os._exit(0) 10 sleep(3) 11 print("New process") 12 else: 13 sleep(5) 14 print("Old process") 15 16 print("Fork test end")
1 import os 2 from time import sleep 3 4 print("=========================") 5 a = 1 6 7 pid = os.fork() 8 9 if pid < 0: 10 print("Create process failed") 11 elif pid == 0: 12 print("New process") 13 print("a = ",a) 14 a = 10000 15 else: 16 sleep(1) 17 print("Old process") 18 print("a:",a) 19 20 print("All a = ",a)
进程相关函数
os.getpid()
- 功能: 获取一个进程的PID值
- 返回值: 返回当前进程的PID
os.getppid()
- 功能: 获取父进程的PID号
- 返回值: 返回父进程PID
1 # 获取pid值 2 3 import os 4 import time 5 6 pid = os.fork() 7 8 if pid < 0: 9 print("Error") 10 elif pid == 0: 11 time.sleep(1) 12 print("Child PID:",os.getpid()) 13 print("Get parent PID:",os.getppid()) 14 else: 15 print("Get child PID:",pid) 16 print("Parent PID:",os.getpid())
os._exit(status)
- 功能: 结束一个进程
- 参数:进程的终止状态
sys.exit([status])
- 功能:退出进程
- 参数:整数 表示退出状态
- 字符串 表示退出时打印内容
1 import os 2 import sys 3 4 # os._exit(1) 5 sys.exit("退出进程") 6 7 print("Process exit")
孤儿和僵尸
1.孤儿进程 : 父进程先于子进程退出,此时子进程成为孤儿进程。
特点: 孤儿进程会被系统进程收养,此时系统进程就会成为孤儿进程新的父进程,孤儿进程退出该进程会自动处理。
2.僵尸进程 : 子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会称为僵尸进程。
特点: 僵尸进程虽然结束,但是会存留部分PCB在内存中,大量的僵尸进程会浪费系统的内存资源。
3.如何避免僵尸进程产生
1)使用wait函数处理子进程退出
```
pid,status = os.wait()
功能:在父进程中阻塞等待处理子进程退出
返回值: pid 退出的子进程的PID status 子进程退出状态 ```
1 import os 2 3 pid = os.fork() 4 5 if pid < 0: 6 print("Error") 7 elif pid == 0: 8 print("Child process",os.getpid()) 9 os._exit(3) 10 else: 11 p,status = os.wait() # 阻塞等待子进程退出 12 print("p : ",p) 13 # 还原退出状态 14 print("status:",os.WEXITSTATUS(status)) 15 while True: 16 pass
2)创建二级子进程处理僵尸
- 父进程创建子进程,等待回收子进程
- 子进程创建二级子进程然后退出
- 二级子进程称为孤儿,和原来父进程一同执行事件
1 import os 2 from time import sleep 3 4 def f1(): 5 for i in range(4): 6 sleep(2) 7 print("写代码") 8 9 def f2(): 10 for i in range(5): 11 sleep(1) 12 print("测代码") 13 14 pid = os.fork() 15 if pid < 0: 16 print("Error") 17 elif pid == 0: 18 p = os.fork() # 二级子进程 19 if p == 0: 20 f2() 21 else: 22 os._exit(0) # 一级子进程退出 23 else: 24 os.wait() # 等一级子进程退出 25 f1()
3)通过信号处理子进程退出
原理: 子进程退出时会发送信号给父进程,如果父进程忽略子进程信号,则系统就会自动处理子进程退出。
方法: 使用signal模块在父进程创建子进程前写如下语句 :
import signal
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
特点 : 非阻塞,不会影响父进程运行。可以处理所有子进程退出
1 import signal 2 import os 3 4 # 子进程退出时父进程会忽略,此时子进程自动由系统处理 5 signal.signal(signal.SIGCHLD,signal.SIG_IGN) 6 7 pid = os.fork() 8 9 if pid < 0: 10 pass 11 elif pid == 0: 12 print("Child pid:",os.getpid()) 13 else: 14 while True: 15 pass