【Python】多进程

操作系统进程相关笔记

提示: 进程牵扯到大量操作系统原理知识,建议先学习《操作系统原理》,再来学习多进程相关内容。


1. 使用 os.fork() 创建多进程

说明:
此方法适用于 Linux 环境。调用 os.fork() 后,若返回值为 0,则证明当前为子进程;否则为父进程。

import os, time

result = os.fork()
print("process pid is:", result)  # 如果输出 0 则证明是子进程
if result == 0:
    print("子进程输出 process")
    time.sleep(20)
    print("子进程 pid is :", os.getpid())
    print("子进程输出父进程 pid is :", os.getppid())
else:
    print("父进程输出 process")
    time.sleep(20)
    print("parent pid is:", os.getpid())

运行后的示例(使用 ps -ef |grep python3 查看进程):

[root@redis-slave-k3s python-test]# ps -ef |grep python3
root      42017   1624  0 11:21 pts/0    00:00:00 python3 os_process.py
root      42018  42017  0 11:21 pts/0    00:00:00 python3 os_process.py

2. 僵尸进程

描述:
当子进程的 PCB(进程控制块)未被父进程回收时,即子进程结束后父进程未调用 waitwaitpid 获取状态,导致子进程的进程描述符仍保留在内存中,这种进程称为僵尸进程

import os, time

result = os.fork()
print("process pid is:", result)  # 如果输出 0 则证明是子进程
if result == 0:
    print("子进程输出 process")
    ## time.sleep(20)  注释此处,让子进程比父进程提前退出
    print("子进程 pid is :", os.getpid())
    print("子进程输出父进程 pid is :", os.getppid())
else:
    print("父进程输出 process")
    time.sleep(20)
    print("parent pid is:", os.getpid())

运行后的示例(使用 ps -ef |grep python3 查看进程):

[root@redis-slave-k3s python-test]# ps -ef |grep python3
root      41654   1624  0 11:20 pts/0    00:00:00 python3 os_process.py
root      41655  41654  0 11:20 pts/0    00:00:00 [python3] <defunct>

3. 孤儿进程

描述:
当父进程退出时,如果子进程仍在运行,此子进程会被 pid 为 1 的进程(通常为 init 或其替代进程)收养,称为孤儿进程

import os, time

result = os.fork()
print("process pid is:", result)  # 如果输出 0 则证明是子进程
if result == 0:
    print("子进程输出 process")
    time.sleep(20)
    print("子进程 pid is :", os.getpid())
    print("子进程输出父进程 pid is :", os.getppid())
else:
    print("父进程输出 process")
    # time.sleep(20)
    print("parent pid is:", os.getpid())

运行后的示例(使用 ps -ef |grep python3 查看进程):

[root@redis-slave-k3s python-test]# ps -ef |grep python3
root      42993      1  0 11:23 pts/0    00:00:00 python3 os_process.py

4. 多进程(multiprocessing 模块)

4.1 基础示例

说明:
以下代码使用 multiprocessing 模块创建了多个进程,并使用 current_process 显示当前进程的信息。代码中将值追加到列表 lst,但注意:每个进程拥有独立内存,子进程中对 lst 的修改不会影响其他进程中的 lst

#!python
# -*- coding: UTF-8 -*-
"""
@Project :sc_learn 
@File    :05多进程.py
@IDE     :PyCharm 
@Author  :Cailuobozi
@Date    :2025/4/13 上午11:29 
"""

from multiprocessing import Process, current_process
import time

lst = []

def task(i):
    print(current_process().name, i, "start....")
    time.sleep(1)
    lst.append(i)
    print(lst, id(lst))
    print(current_process().name, i, "end...")

if __name__ == "__main__":  # 程序入口文件,多进程必须放在入口中运行,否则会报错
    for i in range(4):
        p = Process(target=task, args=(i,))
        p.start()

4.2 自定义进程类

说明:
下面示例展示了如何通过继承 Process 类来自定义进程。自定义类 MyProcess 中重写了 run 方法来定义进程任务。

#!python
# -*- coding: UTF-8 -*-
"""
@Project :sc_learn 
@File    :05多进程.py
@IDE     :PyCharm 
@Author  :Cailuobozi
@Date    :2025/4/13 上午11:29 
"""

from multiprocessing import Process, current_process
import time

class MyProcess(Process):
    def __init__(self, name, delay):
        super().__init__()
        self.name = name
        self.delay = delay

    def run(self):
        """进程执行的任务"""
        print(f"进程 {self.name} 开始运行")
        count = 0
        while count < 3:
            time.sleep(self.delay)
            print(f"{self.name}: 执行时间 {time.ctime(time.time())}")
            count += 1
        print(f"进程 {self.name} 结束")

if __name__ == "__main__":  # 程序入口文件,多进程必须放在入口中运行,否则会报错
    process1 = MyProcess(name="进程A", delay=1)
    process2 = MyProcess(name="进程B", delay=2)

    process1.start()
    process2.start()

    process1.join()
    process2.join()

    print("父进程结束")

进程间通信

消息队列方式

#!python
# -*- coding: UTF-8 -*-


#Queue
from multiprocessing import Process,Queue

def producer(q):
    q.put("Data from producer")

def consumer(q):
    print("Consumer received:",q.get())

if __name__ == '__main__':
    q=Queue()
    p1 = Process(target=producer, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("end.....")

共享内存

#!python
# -*- coding: UTF-8 -*-
from multiprocessing import Process, Value, Lock


def increment(counter, lock):
    with lock:
        counter.value += 1


if __name__ == '__main__':
    counter = Value("i", 0)
    lock = Lock()
    processes = [Process(target=increment, args=(counter, lock)) for _ in range(10)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    print("final counter:", counter.value)

进程池

#!python
# -*- coding: UTF-8 -*-


# 进程池 预创建
from multiprocessing import Pool, current_process
import time

lst = []


def task(i):
    print(current_process().name, i, "start...")
    time.sleep(1)
    lst.append(i)
    print(lst)
    print(current_process().name, i, "end...")


if __name__ == '__main__':
    # 创建进程池,建议设置的进程数和cpu核数一致
    p = Pool(processes=4, maxtasksperchild=2)
    for i in range(20):
        # 进程池接收任务 异步执行单个任务
        p.apply_async(func=task, args=(i,))
    # 关闭进程池  不接受任务
    p.close()
    # 阻塞当前环境
    p.join()
    print("end....")

你可能感兴趣的:(Python,python,开发语言)