Python 多进程

Python的multiprocessing模块允许你创建和管理进程。

多进程是指同时运行多个进程,每个进程都有自己的Python解释器和内存空间。多进程适用于CPU密集型任务,因为每个进程有自己的Python解释器和内存空间,可以在不同的CPU核心上运行,不受GIL的限制。

关键特性

  • 多核处理器的并行计算:由于每个进程有自己的Python解释器和内存空间,它们可以真正并行运行在多核处理器上。
  • 避免GIL:不受全局解释器锁(GIL)的限制,适合CPU密集型任务。
  • 资源共享:提供了多种方式来在进程间共享数据,例如QueuePipeValueArray
  • 进程同步:提供了锁(Lock)、信号量(Semaphore)、条件(Condition)等同步原语。
import time
import multiprocessing

def worker(process_name):
    print(f"{process_name} 开始工作")
    time.sleep(2)  # 模拟工作
    print(f"{process_name} 完成工作")

if __name__ == "__main__":
    # 创建进程
    processes = []
    for i in range(5):
        process = multiprocessing.Process(target=worker, args=(f"进程-{i+1}",))
        processes.append(process)
        process.start()

    # 等待所有进程完成
    for process in processes:
        process.join()

    print("所有进程完成")

进程间通信

在Python中,进程间通信(IPC)是指不同进程之间交换数据的过程。由于Python的multiprocessing模块创建的每个进程都有自己的内存空间,因此进程间不共享内存,需要使用特定的机制来实现通信。以下是multiprocessing模块提供的几种进程间通信的方法:

1. Queue(队列)

Queuemultiprocessing模块中最常用的进程间通信方式,它提供了一个线程和进程安全的队列实现,可以用来在进程间传递消息或数据。

from multiprocessing import Process, Queue

def worker(q):
    for i in range(5):
        q.put(i)
        print(f'Put {i} into queue')

if __name__ == '__main__':
    q = Queue()
    p = Process(target=worker, args=(q,))
    p.start()
    p.join()

    while not q.empty():
        print(f'Get {q.get()} from queue')
2. Pipe(管道)

Pipe提供了一对连接,允许两个进程进行双向通信。每个连接可以用于发送和接收数据。

from multiprocessing import Process, Pipe

def worker(conn):
    conn.send("Hello from worker")
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=worker, args=(child_conn,))
    p.start()
    p.join()

    print(f'Received: {parent_conn.recv()}')
    parent_conn.close()
3. Value(共享值)

Value允许多个进程共享一个简单的数值数据。它使用共享内存,因此进程可以直接访问这个值。

from multiprocessing import Process, Value

def worker(num):
    num.value = 3.14

if __name__ == '__main__':
    num = Value('d', 0.0)
    p = Process(target=worker, args=(num,))
    p.start()
    p.join()

    print(f'Value from main: {num.value}')
4. Array(共享数组)

Array类似于Value,但它用于共享一维数组。

from multiprocessing import Process, Array

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

if __name__ == '__main__':
    arr = Array('i', range(5))
    p = Process(target=worker, args=(arr,))
    p.start()
    p.join()

    print(f'Array from main: {arr[:]}')
  • 数据类型:在使用ValueArray时,需要指定正确的数据类型。
  • 同步:虽然QueuePipe是线程安全的,但在使用时可能仍需要考虑同步问题,尤其是在多个进程同时访问同一个队列或管道时。
  • 内存管理ValueArray使用共享内存,这意味着它们在进程间共享数据时比通过序列化传递数据更高效。
  • 错误处理:在使用进程间通信时,应当妥善处理可能出现的错误,例如在Queue操作中可能会抛出的FullEmpty异常。

进程池

ProcessPoolExecutor

进程池可以通过concurrent.futures模块中的ProcessPoolExecutor类实现的。这个类提供了一个接口,允许你异步地执行可调用对象,并将任务分派到多个进程。

from concurrent.futures import ProcessPoolExecutor

def task(n):
    return n * n

if __name__ == '__main__':
    with ProcessPoolExecutor() as executor:
        # submit方法提交任务并获取Future对象
        future = executor.submit(task, 10)
        # 等待任务完成并获取结果
        result = future.result()
        print(f"任务结果:{result}")
        

        # 并发执行多个任务
        results = executor.map(task, [1, 2, 3, 4, 5])
        for result in results:
            print(f"任务结果:{result}")
multiprocessing.Pool

multiprocessing模块也提供了一个Pool类,类似于concurrent.futures.ProcessPoolExecutor,可以方便地并行执行多个任务。

from multiprocessing import Pool

def worker(x):
    return x * x

if __name__ == '__main__':
    with Pool(5) as p:  # 创建一个包含5个进程的进程池
        results = p.map(worker, range(10))  # 将任务分配给进程池中的进程
    print(results)

多进程使用

  • 安全启动:在使用ProcessPoolExecutor时,确保你的代码包含if __name__ == '__main__':,以防止在Windows上无限递归创建子进程。
  • 资源共享:由于进程间不共享内存,所以需要使用multiprocessing模块提供的机制来共享数据。
  • 进程同步:当多个进程需要访问共享资源时,需要使用同步原语来避免竞态条件。
  • 性能考虑:创建进程比创建线程成本更高,因为每个进程需要独立的内存空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值