Python使用multiprocessing库实现多进程

在Python中执行数据处理任务时,可能执行非常缓慢,这时可以将一个进程任务拆分为多个子进程,利用CPU的多个核心并发执行多个进程的方式来加速程序的执行。python中用于处理多进程相关的包为multiprocessing,通过Process、Queue、Pipe、Lock等类实现子进程、通信和共享数据、进程同步等功能。

1、进程的创建和执行

有两种创建子进程的方式,第一种是直接通过Process()创建子进程对象,第二种是通过继承multiprocessing.Process类的方式,先创建子进程类然后再实例化子进程对象。

Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None),其中target为子进程要执行的函数名称,args以元组的方式为函数传入参数。生成的对象通过start()开始执行进程,is_alive()返回是否存活,通过pidname属性获取进程id和名字。join()会阻塞调用进程指导本进程执行结束,terminate()终止进程。

如下所示,创建多个子进程并启动,注意不可以通过for循环来启动子进程,那样子进程会依次执行,而不是并发。程序运行后等待两秒后一同输出“第1/2/3个子进程”

import time
from multiprocessing import Process

def process_func(num):
    time.sleep(2)
    print('第', num, '个进程')


if __name__ == '__main__':
    process_list = []
    # 循环创建多个子进程
    for i in range(3):
        p = Process(target=process_func, args=(i+1,))
        process_list.append(p)

    # 依次启动进程
    process_list[0].start()
    process_list[1].start()
    process_list[2].start()

如下通过类继承的方式创建子进程类,在__init__()方法中接收参数,并重写run()方法来定义子进程所需要执行的操作

class ClockProcess(Process):
    def __init__(self, num):	# 接收参数
        Process.__init__(self)
        self.num = num
	
    def run(self):				# 定义子进程执行的操作
        time.sleep(2)
        print('第', self.num, '个进程')


if __name__ == '__main__':
    p4 = ClockProcess(4)
    p4.start()

守护进程:如果子进程的daemon属性设置为True,则其在主进程结束后会自动结束子进程,

def process_func(num):
    time.sleep(2)
    print('第', num, '个进程')


if __name__ == '__main__':
    p = Process(target=process_func, args=(5,))
    # p.daemon = True								# 在start()之前开启daemon属性
    p.start()
    print('主进程结束')

上面的程序运行结果如下,主进程在开启子进程后继续运行,输出“主进程结束”,子进程继续执行,先休眠两秒,然后输出“第 5 个进程”

主进程结束
第 5 个进程

但是在设置p.daemon = True,运行只输出“主进程结束”,子进程不会输出,说明主进程结束后子进程也随之结束

进程阻塞:通过join()方法可以阻塞调用进程,直到子进程运行结束,例如下面程序在使用p.join()阻塞主进程,主进程会等待子进程运行结束输出“第 5 个进程”,再继续执行输出“主进程结束”,

if __name__ == '__main__':
    p = Process(target=process_func, args=(5,))
    p.daemon = True
    p.start()
    p.join()					# 阻塞进程
    print('主进程结束')
'''
第 5 个进程
主进程结束
'''

2、互斥与同步

Lock锁

multiprocessing提供了Lock类用于实现进程锁机制,可以使用with的方式来进行锁管理,或者手动使用lock.acquire()、lock.release()来获取或者释放锁。如下所示连个进程分别对文件进行写入,通过锁管理,实现了一个进程写完之后,另一个进程再写入

import multiprocessing


def prcess1(lock, f):
    with lock:  # 使用with进行锁管理
        fs = open(f, 'a+')
        n = 3
        while n > 1:
            fs.write("进程1写入文件\n")
            n -= 1
        fs.close()


def process2(lock, f):
    lock.acquire()  # 获取锁
    try:
        fs = open(f, 'a+')
        n = 3
        while n > 1:
            fs.write("进程2写入文件\n")
            n -= 1
        fs.close()
    finally:
        lock.release()  # 释放锁


if __name__ == "__main__":
    lock = multiprocessing.Lock()
    f = "file.txt"
    w = multiprocessing.Process(target=prcess1, args=(lock, f))
    nw = multiprocessing.Process(target=process2, args=(lock, f))
    w.start()
    nw.start()
'''
file.txt
进程2写入文件
进程2写入文件
进程1写入文件
进程1写入文件
'''

信号量Semaphore

为了互斥对多个同类资源的访问,引入了信号量机制,它和锁不同之处在于Lock每次只允许一个进程获得锁,Semaphore可以指定同时有多个进程获得资源

import multiprocessing
import time


def worker(s):
    s.acquire()
    print(multiprocessing.current_process().name + "acquire")
    time.sleep(2)
    print(multiprocessing.current_process().name + "release\n")
    s.release()


if __name__ == "__main__":
    s = multiprocessing.Semaphore(2)  # 最大资源数为2
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(s,))
        p.start()
'''
Process-2acquire
Process-3acquire
Process-3release

Process-2release

Process-1acquire
Process-4acquire
Process-1release

Process-4release

Process-5acquire
Process-5release
'''

Event同步

multiprocessing提供了Event用于实现进程之间的同步,例如下面的进程2开始执行后,通过wait()等待event,进程1通过set()触发event后,进程2再继续执行

def process1(e):
    time.sleep(2)
    e.set()  # 通过set()触发event
    print('子进程1触发event')


def process2(e):
    print('进程2等待中。。。')
    e.wait()  # 等待event被触发
    print('子进程2继续执行')


if __name__ == "__main__":
    e = multiprocessing.Event()
    p1 = multiprocessing.Process(target=process1, args=(e,))
    p2 = multiprocessing.Process(target=process2, args=(e,))
    p1.start()
    p2.start()
    print('主进程结束')
'''
主进程结束
进程2等待中。。。
子进程1触发event
子进程2继续执行
'''

3、进程通信

队列Queue

multiprocessing提供了Queue类来实现进程之间数据的传递。
通过put()将数据放入队列,当队列满时,如果属性block=False会立即抛出异常queues.Full;若block为True(默认值),会等待timeout的时间再尝试放入,失败后抛出异常。
通过get()从队列取出数据,同样地在队列为空时,若block=False会抛出异常queues.Empty;block=True会等待timeout的时间取出

如下所示写进程write_process每隔两秒写入队列,读进程read_process接收数据

def write_process(q):
    try:
        for i in range(3):
            time.sleep(2)
            q.put(1, block=True, timeout=2)     # 将数据放入队列
    except multiprocessing.queues.Full:
        print('队列已满')


def read_process(q):
    try:
        for i in range(3):
            msg = q.get()       # 从队列读取数据
            print('读进程接收到:', msg)
    except multiprocessing.queues.Empty:
        print('队列为空')


if __name__ == "__main__":
    q = multiprocessing.Queue(2)    # 大小为2的队列
    p1 = multiprocessing.Process(target=write_process, args=(q,))
    p2 = multiprocessing.Process(target=read_process, args=(q,))
    p1.start()
    p2.start()
    print('主进程结束')
'''
主进程结束
读进程接收到: 1
读进程接收到: 1
读进程接收到: 1
'''

管道Pipe

与只能一端写、一端读的Queue相比,Pipe在全双工模式下两端可以同时进行读写。其构造方法Pipe()会返回管道的两端(pipe1, pipe2), 默认指定属性duplex=True开启全双工模式,这时pipe1、pipe2都可以进行读写。若设置duplex=False,则pipe1只能读,pipe2只能写。
pipe通过send()发送信息,recv()接收信息。

def process1(pipe):
    for i in range(3):
        pipe.send(i)
        time.sleep(2)
        print('进程1收到信息:', pipe.recv())


def process2(pipe):
    for i in range(3):
        pipe.send(i)
        time.sleep(2)
        print('进程2收到信息:', pipe.recv())


if __name__ == "__main__":
    (pipe1, pipe2) = multiprocessing.Pipe()  # 全双工模式管道
    p1 = multiprocessing.Process(target=process1, args=(pipe1,))
    p2 = multiprocessing.Process(target=process2, args=(pipe2,))
    p1.start()
    p2.start()
'''
进程2收到信息: 0
进程1收到信息: 0
进程1收到信息: 1
进程2收到信息: 1
进程2收到信息: 2
进程1收到信息: 2
'''

4、进程池Pool

当进程数量较少时,我们可以手动创建分配进程的执行,但是当进程数量较多时,手动分配就不太现实,而且处理器同时可以执行的进程数是有限制的,这时可以使用进程池来自动分配进程资源。当进程池中有空闲的进程资源时,就会自动分配给请求并执行,如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会分配新的进程给请求。

通过Pool()来创建进程池,processes属性指定最大进程池数。通过apply_async()以异步的方式分配进程,apply()以阻塞的方式。close()关闭进程池

如下所示,首先创建大小为2的进程池,然后循环提交3个进程请求,由于进程池大小为2,进程0、1先执行,结束后,进程池再分配资源执行进程2

def process(i):
    print('执行进程:', i)
    time.sleep(2)
    print('进程', i, '执行结束')


if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=2)  # 创建大小为2的进程池
    for i in range(3):
        pool.apply_async(func=process, args=(i,))  # 异步的方式分配进程

    print('主进程继续执行')
    pool.close()	# 关闭进程池
    pool.join()  # 阻塞主进程直到进程池运行结束
    print('主进程执行结束')
'''
主进程继续执行
执行进程: 0
执行进程: 1
进程 0 执行结束
进程 1 执行结束
执行进程: 2
进程 2 执行结束
主进程执行结束
'''

所谓异步调用是指发起任务后必须不用等待执行任务,可以立即开启执行其他操作,相对地同步调用是发起任务后必须在原地等待任务执行完成,才能继续执行。上面的例子中使用apply_async()以异步的方式分配进程,可见分配进程之后主进程不等待子进程的执行,输出“主进程继续执行”。当采用apply()分配进程时,执行顺序如下,可见进程0开始执行后并没有继续执行其他进程,而是等待执行结束后才继续执行进程1.这样的方式并不能利用多进程并发的优势。

执行进程: 0
进程 0 执行结束
执行进程: 1
进程 1 执行结束
执行进程: 2
进程 2 执行结束
主进程继续执行
主进程执行结束

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 下面是一个使用python `multiprocessing` 模块实现多进程的示例代码: ``` import multiprocessing def worker(number): print(f'Worker {number} is running') if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=worker, args=(i,)) p.start() ``` 这段代码创建了5个进程,每个进程都执行`worker`函数,并打印出进程编号。 ### 回答2: 下面是一个使用Python multiprocessing模块实现多进程的示例代码: ```python import multiprocessing def worker(name): print(f'Worker {name} 执行') if __name__ == '__main__': processes = [] for i in range(5): p = multiprocessing.Process(target=worker, args=(i,)) processes.append(p) p.start() for p in processes: p.join() ``` 以上代码创建了5个进程,并通过worker函数在每个进程中执行一些任务。在主程序的主函数中,先创建一个进程列表用于存储即将被创建的进程对象。 在for循环中,通过multiprocessing.Process类创建一个进程对象,将要执行的任务指定为worker函数,并传递一个参数i给worker函数。然后将新创建的进程对象添加到进程列表中。 接着,使用p.start()启动每个进程。 最后,使用p.join()等待每个进程执行完毕,确保所有进程都执行完毕后再继续主程序的执行。 运行以上代码,你会看到五个进程同时被创建并执行,不同进程之间的输出顺序可能会有不同。 ### 回答3: 多进程可以通过Pythonmultiprocessing模块来实现。下面是一个使用Python multiprocessing模块实现多进程的示例代码: ```python import multiprocessing def worker(num): """Worker function""" print(f'Worker {num} started') # do some work print(f'Worker {num} finished') if __name__ == '__main__': # 创建多个进程 processes = [] for i in range(5): p = multiprocessing.Process(target=worker, args=(i,)) processes.append(p) p.start() # 等待进程结束 for process in processes: process.join() ``` 在上述代码中,我们首先定义了worker函数作为每个进程要执行的任务。然后,在主程序中使用for循环创建了5个进程,并将它们存储在一个列表中。每个进程使用multiprocessing.Process类创建,并指定了要执行的目标函数和传递给它的参数。然后,我们通过调用start()方法来启动每个进程。 在所有进程都启动后,我们通过调用join()方法来等待每个进程的结束。这样可以确保主程序在所有子进程执行完毕之前不会退出。 运行上面的代码,你会看到每个进程都会输出"Worker x started"和"Worker x finished"的信息,其中x是进程的编号。 使用Pythonmultiprocessing模块可以帮助我们实现多进程编程,从而在计算机上同时执行多个任务,提高程序的运行效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值