Python 中的进程创建

进程是操作系统进行资源分配和调度的基本单位 ,每个进程都有独立的内存空间文件描述符执行状态 。Python 通过 multiprocessing 模块支持多进程编程,用于充分利用多核 CPU

一、进程 vs 线程

特性 进程 线程
内存空间 独立,互不干扰 共享进程的内存
数据隔离 天然隔离,需要 IPC 共享数据需要加锁
创建开销 大(复制内存)
切换开销 大(切换页表)
GIL 影响 无影响,真正并行 受 GIL 限制
适用场景 CPU 密集型 I/O 密集型
复制代码
# 进程的独立内存空间
from multiprocessing import Process

data = []  # 全局列表

def worker():
    data.append(1)  # 每个进程有自己的 copy
    print(f"进程 {id(data)}: {data}")

p1 = Process(target=worker)
p2 = Process(target=worker)
p1.start()
p2.start()
p1.join()
p2.join()
# 输出:不同进程的 data 互不影响

二、创建进程

1. 使用 Process

复制代码
from multiprocessing import Process
import os

def worker(name, num):
    print(f"进程 {name}: PID={os.getpid()}, 父进程={os.getppid()}")
    return num * 2

# 方式1:直接传入函数
p = Process(target=worker, args=("worker1", 100))
p.start()      # 启动进程
p.join()       # 等待进程结束

# 方式2:自定义进程类
class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name
    
    def run(self):
        print(f"运行进程: {self.name}")

p = MyProcess("my_worker")
p.start()
p.join()

2. 进程启动方式

复制代码
import multiprocessing as mp

# 设置启动方式(必须在 if __name__ == '__main__' 内)
if __name__ == '__main__':
    mp.set_start_method('spawn')  # Windows 默认
    # mp.set_start_method('fork')   # Linux/macOS 默认

# 三种方式对比:
# | spawn  | 全新启动,不继承父进程资源 | Windows、macOS |
# | fork   | 复制父进程(不安全) | Linux |
# | forkserver | 通过服务进程 fork(安全) | Unix-like |

三、进程池(Pool)

复制代码
from multiprocessing import Pool
import time

def cpu_intensive(n):
    """CPU 密集型任务"""
    return sum(i * i for i in range(n))

if __name__ == '__main__':
    with Pool(processes=4) as pool:
        # map:阻塞,保持顺序
        results = pool.map(cpu_intensive, [10**7] * 4)
        print(results)
        
        # map_async:异步非阻塞
        result = pool.map_async(cpu_intensive, [10**7] * 4)
        print("异步提交完成")
        results = result.get()  # 等待结果
        
        # apply_async:单任务异步
        async_result = pool.apply_async(cpu_intensive, (10**7,))
        result = async_result.get(timeout=30)

四、进程间通信(IPC)

1. Queue(队列)

复制代码
from multiprocessing import Process, Queue

def producer(q):
    for i in range(5):
        q.put(f"消息{i}")
        print(f"生产: {i}")
    q.put(None)  # 结束标志

def consumer(q):
    while True:
        msg = q.get()
        if msg is None:
            break
        print(f"消费: {msg}")

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()

2. Pipe(管道)

复制代码
from multiprocessing import Process, Pipe

def worker(conn):
    conn.send([1, 2, 3])
    print(f"收到父进程消息: {conn.recv()}")
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=worker, args=(child_conn,))
    p.start()
    print(f"收到子进程数据: {parent_conn.recv()}")
    parent_conn.send("来自父进程")
    p.join()

3. Shared Memory(共享内存)

复制代码
from multiprocessing import Process, Value, Array

def worker(val, arr):
    val.value += 1
    for i in range(len(arr)):
        arr[i] += i

if __name__ == '__main__':
    num = Value('i', 0)        # 'i' 表示有符号整数
    arr = Array('d', [0.0, 1.0, 2.0])  # 'd' 表示 double
    
    processes = [Process(target=worker, args=(num, arr)) for _ in range(4)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    
    print(f"num: {num.value}")
    print(f"arr: {arr[:]}")

4. Manager(管理器)

复制代码
from multiprocessing import Process, Manager

def worker(d, l, key, value):
    d[key] = value
    l.append(value)

if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
        l = manager.list()
        
        processes = [Process(target=worker, args=(d, l, f"key{i}", i)) for i in range(5)]
        for p in processes: p.start()
        for p in processes: p.join()
        
        print(f"dict: {d}")
        print(f"list: {l}")

五、进程同步(锁)

复制代码
from multiprocessing import Process, Lock, Value

def worker(lock, counter):
    for _ in range(1000):
        with lock:
            counter.value += 1

if __name__ == '__main__':
    counter = Value('i', 0)
    lock = Lock()
    
    processes = [Process(target=worker, args=(lock, counter)) for _ in range(10)]
    for p in processes: p.start()
    for p in processes: p.join()
    
    print(f"最终值: {counter.value}")  # 应该是 10000

六、进程 vs 线程 性能对比

复制代码
from multiprocessing import Process
from threading import Thread
import time

def cpu_task():
    for i in range(10**7):
        pass

def io_task():
    time.sleep(0.1)

if __name__ == '__main__':
    import time
    
    # CPU 密集型:多进程更快(利用多核)
    start = time.time()
    processes = [Process(target=cpu_task) for _ in range(4)]
    for p in processes: p.start()
    for p in processes: p.join()
    print(f"多进程CPU任务: {time.time() - start:.2f}s")
    
    # I/O 密集型:多线程更快(切换开销小)
    start = time.time()
    threads = [Thread(target=io_task) for _ in range(40)]
    for t in threads: t.start()
    for t in threads: t.join()
    print(f"多线程I/O任务: {time.time() - start:.2f}s")

结果(4核CPU):

复制代码
多进程CPU任务: 1.8s   # 并行利用多核
多线程CPU任务: 6.5s   # 受 GIL 限制
多进程I/O任务: 0.45s  # 进程开销大
多线程I/O任务: 0.12s  # 线程开销小
相关推荐
李可以量化12 分钟前
Tornado 从入门到精通(二)下:协程调用方式与经典使用模式
python
雪碧透心凉_20 分钟前
Python OpenCV图像处理入门
图像处理·python·opencv
李可以量化35 分钟前
Tornado 从入门到精通(二)上:协程核心机制详解
python
晴天1637 分钟前
AgentLoop分享(上): 让 AI 真正“自主干活“-Day15
人工智能·python
Patrick在香港1 小时前
Python爬虫框架实战:优雅抓取香港政府公开API数据的通用方案
java·开发语言·爬虫·python·ai编程·数据可视化·可用性测试
李白的天不白1 小时前
python下载脚本
python
2501_909509101 小时前
DAY 45
python
郝学胜_神的一滴1 小时前
Python 高级编程 027:四大推导式全攻略
python·pycharm
菜冻鱼2 小时前
Python-sklearn-特征工程
开发语言·人工智能·python·机器学习·numpy·matplotlib·sklearn
mit6.8242 小时前
archived
后端·python·flask