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  # 线程开销小
相关推荐
信誓旦旦的程序猿11 小时前
【Python量化实战宝典 #21】北向资金跟随手册:聪明钱择时信号(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
严谨的麻辣烫11 小时前
静态 ISP 代理请求超时怎么排查?Python 与 curl 实战
python·http·requests·1024程序员节·网络排障
KeepRobots13 小时前
11-01 温哥华不回拨:用 60 行 Python 查你的工单系统会不会差一小时(KeepRobots 工程笔记)
python
xiao77mwq13 小时前
你以为 OCR 慢?实测 81.3 s 里全是故障代价:如何把「定格态」消掉,让耗时从 6.5 s 到 13 倍差距显出原形
python
深圳市益普科技有限公司13 小时前
半导体良率管理YMS:良率与设备参数的相关性,先拉哪几组数据
人工智能·python·算法
“AI国潮设计-小江”13 小时前
【AIGC实战】Python+SDXL打造“潮汕英歌舞IP”万能立牌插件,批量生成“发财元宝蛋糕”视觉营销方案(附源码)
开发语言·人工智能·python·prompt·aigc
砚底藏山河14 小时前
python量化实操:冷热分层存储
java·开发语言·python·金融
十五年专注C++开发14 小时前
pybind11:一个跨C++和Python平台的编程库
开发语言·c++·python·pybind11
炘爚14 小时前
数据结构算法总结
数据结构·python·算法
信誓旦旦的程序猿14 小时前
【Python量化实战宝典 #18】MACD 金叉死叉手册:DIF、DEA、柱体全拆解(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口