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内不会有数据。