Python进程模块之multiprocessing模块(第6节)


multiprocessing模块

multiprocessing模块是Python标准库中提供的一个用于实现多进程编程的模块。multiprocessing模块和threading类实现多线程的效果类似,但是multiprocessing模块创建的是子进程而不是子线程,所以可以有效地避免全局解释锁和充分地使用多核CPU的资源,提高程序的执行效率,同时也可以实现进程间通信和数据共享。例如:

动手练一练:

import multiprocessing
import time

def worker(n):
    """该函数将在子进程中执行"""
    print("第", n, "个进程开始执行时间:", time.ctime())
    time.sleep(2)
    print("第", n, "个进程结束执行时间:", time.ctime())

if __name__ == '__main__':
    processes = []

    #开启3个子进程执行worker函数
    for i in range(3):
        # 实例化进程对象
        p = multiprocessing.Process(target=worker, args=(i,)) # (i,)必须加“,”号,否则不认这是个元组
        # 启动子进程
        p.start()
        processes.append(p)

    for p in processes:
        # 等待子进程结束
        p.join()

执行以上代码,输出结果为:

 0 个进程开始执行时间 Sun May 5 10:39:30 2024
 0 个进程结束执行时间 Sun May 5 10:39:32 2024
 1 个进程开始执行时间 Sun May 5 10:39:30 2024
 1 个进程结束执行时间 Sun May 5 10:39:32 2024
 2 个进程开始执行时间 Sun May 5 10:39:30 2024
 2 个进程结束执行时间 Sun May 5 10:39:32 2024

上面的例子中,通过multiprocessing模块的multiprocessing.Process创建进程对象,和threading.Thread的使用方法一致,指定target参数为worker()函数,通过args参数传递元组来作为函数的参数传递,然后通过start()方法启动子进程,用join()方法来阻塞等待进程执行结束。

同样,multiprocessing模块还可以通过继承multiprocessing.Process类的方式,派生一个子类来创建进程并实现run方法。例如:

动手练一练:

import multiprocessing
import time

 # 继承Process类
class MyProcess(multiprocessing.Process):
    def __init__(self,name):
        super(MyProcess,self).__init__()
        self.name = name

    def run(self):
        """该函数将在子进程中执行"""
        print("第", self.name, "个进程开始执行时间:", time.ctime())
        time.sleep(2)
        print("第", self.name, "个进程结束执行时间:", time.ctime())

if __name__ == '__main__':
    processes = []

    #开启3个子进程执行worker函数
    for i in range(3):
        # 实例化进程对象
        p = MyProcess(str(i))
        # 启动子进程
        p.start()
        processes.append(p)

    for p in processes:
        # 等待子进程结束
        p.join()

执行以上代码,输出结果为:

 0 个进程开始执行时间 Sun May 5 11:04:02 2024
 0 个进程结束执行时间 Sun May 5 11:04:04 2024
 1 个进程开始执行时间 Sun May 5 11:04:02 2024
 1 个进程结束执行时间 Sun May 5 11:04:04 2024
 2 个进程开始执行时间 Sun May 5 11:04:02 2024
 2 个进程结束执行时间 Sun May 5 11:04:04 2024

上面的例子中,通过multiprocessing.Process类的派生类MyProcess实现的效果和直接通过multiprocessing.Process类实现的效果一模一样。派生类MyProcess中重写了父类multiprocessing.Process的run()方法,创建一个子进程MyProcess类的对象后再调用start()方法就能启动子进程,并运行run()方法中的代码。

在multiprocessing模块中有一个Queue对象,使用方法和多线程中的Queue对象一样,区别是多线程Queue对象是线程安全的,无法在进程之间通信。而multiprocess.Queue可以在进程间通信。

multiprocessing模块中的Queue对象是一个进程间通信的队列,它可以在多个进程之间提供一个安全的数据传输方式。例如:

动手练一练:

import multiprocessing
import time

# 创建一个Queue对象
MyQueue = multiprocessing.Queue()

 # 继承Process类
class MyProcess(multiprocessing.Process):
    def __init__(self, n, s):
        super(MyProcess,self).__init__()
        self.n = n
        self.s = s

    def run(self):
        # 编辑队列内容
        out = "第" + self.s + "个进程开始执行时间:" + time.ctime() + "\n"
        time.sleep(2)
        out += "第" + self.s + "个进程结束执行时间:" + time.ctime()
        # 向Queue队列中添加内容
        self.n.put(out)

def main():
    processes = []

    # 创建进程并把MyQueue队列传递给进程
    for i in range(3):
        processes.append(MyProcess(MyQueue, str(i)))

    # 启动进程
    for i in range(3):
        processes[i].start()

    # 等待进程结束
    for i in range(3):
        processes[i].join()

    # 读取队列内容
    while not MyQueue.empty():
        result = MyQueue.get()
        print(result)

if __name__ == '__main__':
    main()

执行以上代码,输出结果为:

第0个进程开始执行时间Sun May 5 12:26:04 2024
第0个进程结束执行时间Sun May 5 12:26:06 2024
第1个进程开始执行时间Sun May 5 12:26:04 2024
第1个进程结束执行时间Sun May 5 12:26:06 2024
第2个进程开始执行时间Sun May 5 12:26:04 2024
第2个进程结束执行时间Sun May 5 12:26:06 2024

这里需要注意的是,线程可以通过全局变量来共享数据,但是进程之间不会共享数据。所以在multiprocessing模块的多进程中使用Queue对象的时候,虽然multiprocessing.Queue()的方法和线程中的queue.Queue()方法类似,但是在创建进程的时候需要吧Queue对象以参数的形式传递给MyProcess进程,这样才能正确地让主进程获取子进程的数据,否则主进程的Queue内不会有数据。