教育行业A股IPO第一股(股票代码 003032)

全国咨询/投诉热线:400-618-4000

Python编程之多进程(multiprocessing)详解

更新时间:2023年04月04日10时53分 来源:传智教育 浏览次数:

好口碑IT培训

  Python中的multiprocessing模块提供了一种创建和管理进程的方式,使得可以利用多个CPU来加速程序运行。在这里,我会详细介绍Python中的多进程编程,包括以下内容:

  一.多进程概念

  二.multiprocessing模块介绍

  三.进程池

  四.进程通信

  五.multiprocessing的一些注意事项

  一.多进程概念

  多进程是指在同一时间内,同时执行多个程序或多个部分的程序。每个进程都拥有自己的地址空间、内存、文件描述符和其他系统资源。多进程的好处在于可以使程序并行执行,从而提高程序的运行效率。

  二.multiprocessing模块介绍

  multiprocessing模块提供了一个Process类,可以用来创建和管理进程。下面是一个简单的示例:

import multiprocessing

def worker():
    """该函数将在子进程中执行"""
    print('Worker')

if __name__ == '__main__':
    # 创建子进程
    p = multiprocessing.Process(target=worker)
    # 启动子进程
    p.start()
    # 等待子进程结束
    p.join()

  在上面的代码中,worker函数将在子进程中执行。首先,创建了一个Process对象,指定target参数为worker函数。然后,通过调用start方法启动子进程,最后调用join方法等待子进程结束。

  三. 进程池

  如果需要创建大量的进程,那么使用Process类可能会导致系统资源的浪费。此时,可以使用Pool类来创建进程池。下面是一个简单的示例:

import multiprocessing

def worker(num):
    """该函数将在子进程中执行"""
    print('Worker %d' % num)

if __name__ == '__main__':
    # 创建进程池
    pool = multiprocessing.Pool(4)
    # 启动进程池中的进程
    pool.map(worker, range(10))
    # 关闭进程池
    pool.close()
    # 等待进程池中的进程结束
    pool.join()

  在上面的代码中,Pool类的构造函数中指定了进程池的大小为4,然后通过调用map方法来启动进程池中的进程。map方法会将worker函数和range(10)序列中的每个元素一一对应,然后将它们作为参数传递给进程池中的进程。最后,调用close方法关闭进程池,并调用join方法等待所有进程结束。

  四. 进程通信

  在多进程编程中,不同的进程之间需要进行通信。multiprocessing模块提供了多种进程间通信的方式,例如使用队列、管道、共享内存等。

  (1)队列

  队列是一种常用的进程间通信方式。multiprocessing模块中提供了Queue类,可以用来创建队列。下面是一个简单的示例:

import multiprocessing

def producer(q):
    """该函数将在生产者进程中执行"""
    for i in range(10):
        q.put(i)

def consumer(q):
    """该函数将在消费者进程中执行"""
    while True:
        item = q.get()
        if item is None:
            break
        print(item)

if __name__ == '__main__':
    # 创建队列
    q = multiprocessing.Queue()
    # 创建生产者进程
    p1 = multiprocessing.Process(target=producer, args=(q,))
    # 创建消费者进程
    p2 = multiprocessing.Process(target=consumer, args=(q,))
    # 启动进程
    p1.start()
    p2.start()
    # 等待进程结束
    p1.join()
    # 发送结束信号
    q.put(None)
    p2.join()

  在上面的代码中,首先创建了一个Queue对象,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用put方法将0~9的数字放入队列中,消费者进程通过调用get方法从队列中获取数据,并将其打印出来。最后,调用put方法发送结束信号,然后等待两个进程结束。

  (2)管道

  管道是另一种常用的进程间通信方式。multiprocessing模块中提供了Pipe类,可以用来创建管道。下面是一个简单的示例:

import multiprocessing

def producer(conn):
    """该函数将在生产者进程中执行"""
    for i in range(10):
        conn.send(i)
    conn.close()

def consumer(conn):
    """该函数将在消费者进程中执行"""
    while True:
        item = conn.recv()
        if item is None:
            break
        print(item)

if __name__ == '__main__':
    # 创建管道
    conn1, conn2 = multiprocessing.Pipe()
    # 创建生产者进程
    p1 = multiprocessing.Process(target=producer, args=(conn1,))
    # 创建消费者进程
    p2 = multiprocessing.Process(target=consumer, args=(conn2,))
    # 启动进程
    p1.start()
    p2.start()
    # 等待进程结束
    p1.join()
    # 发送结束信号
    conn1.send(None)
    p2.join()

  在上面的代码中,首先创建了一个管道,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用send方法将0~9的数字发送到管道中,消费者进程通过调用recv方法从管道中获取数据,并将其打印出来。最后,调用send方法发送结束信号,然后等待两个进程结束。

  (3)共享内存

  共享内存是一种高效的进程间通信方式,它允许多个进程共享同一块内存区域。multiprocessing模块中提供了Value和Array类,可以用来创建共享内存。下面是一个简单的示例:

import multiprocessing

def worker1(n):
    """该函数将在进程1中执行"""
    n.value += 1
    print('worker1:', n.value)

def worker2(n):
    """该函数将在进程2中执行"""
    n.value += 1
    print('worker2:', n.value)

if __name__ == '__main__':
    # 创建共享内存
    n = multiprocessing.Value('i', 0)
    # 创建进程1
    p1 = multiprocessing.Process(target=worker1, args=(n,))
    # 创建进程2
    p2 = multiprocessing.Process(target=worker2, args=(n,))
    # 启动进程
    p1.start()
    p2.start()
    # 等待进程结束
    p1.join()
    p2.join()

  在上面的代码中,首先创建了一个Value对象,用于存储一个整数值。然后创建了两个进程,每个进程都会将共享内存中的值加1,并将其打印出来。最后,等待两个进程结束。

  除了Value类之外,multiprocessing模块还提供了Array类,用于创建共享内存数组。下面是一个简单的示例:

  在上面的代码中,首先创建了一个Array对象,用于存储一个整数数组。然后创建了两个进程,每个进程都会将共享内存数组中的第一个元素加1,并将其打印出来。最后,等待两个进程结束。

  五.multiprocessing的一些注意事项

  在使用 multiprocessing 模块进行多进程编程时,需要注意以下几点:

  1.全局变量的共享问题

  每个子进程都有自己的内存空间,因此全局变量在多进程之间不能直接共享。如果需要共享数据,可以使用 multiprocessing.Value 或 multiprocessing.Array 来创建共享内存。

  2.进程间通信问题

  多个进程之间需要相互通信,可以使用 multiprocessing.Queue 或 multiprocessing.Pipe 来进行进程间通信。

  3.进程池的使用

  如果需要同时启动多个进程,可以使用进程池来管理进程。进程池可以避免频繁地启动和关闭进程所带来的开销,提高程序的效率。

  4.子进程的异常处理

  每个子进程都是一个独立的进程,当子进程出现异常时,主进程并不会收到通知。因此需要在子进程中进行异常处理,并将异常信息通过进程间通信的方式传递给主进程。

  5.进程的启动方式

  可以使用 multiprocessing.Process 来创建进程,也可以使用 multiprocessing.Pool 来创建进程池。进程池可以方便地管理多个进程,避免手动启动和关闭进程所带来的麻烦。

0 分享到:
和我们在线交谈!