前言多处理库基于线程API,它将工作分成多个进程。在某些情况下,多进程可以作为临时替代线程来利用多个CPU内核,并相应地避免Python全局解释器锁导致的计算瓶颈。接下来,让我们看看多处理库的创建过程与线程库有何相似之处。创建进程要创建进程,最简单的方法是实例化一个带有目标函数的Process对象,然后像线程一样调用start()函数使其工作。示例如下:importmultiprocessingdefworker():foriinrange(3):print(i)if__name__=="__main__":p=multiprocessing.Process(target=worker)p.start()运行后效果如下:需要注意的是,multiprocessing库在Windows上创建的进程必须在if__name__=="__main__":中,这是多进程在Windows上的实现。在Windows上,子进程会自动导入启动它的文件,导入时会执行这些语句。如果直接创建,会无限递归创建子进程,报错。所以创建子进程的部分一定要用那个if判断来保护。导入时__name__不是__main__,不会递归运行。设置进程名在threading线程中,我们可以通过它的参数名来设置线程名,也可以通过name参数来设置进程名。示例如下:importmultiprocessingimporttimedefworker():print(multiprocessing.current_process().name,"start")time.sleep(2)print(multiprocessing.current_process().name,"end")if__name__=="__main__":p1=multiprocessing.Process(name='p1',target=worker)p2=multiprocessing.Process(name='p2',target=worker)p3=multiprocessing.Process(name='p3',target=worker)p1.start()p2.start()p3.start()运行后效果如下:守护进程和线程一样,等所有子进程都没有退出后,主程序才会退出。有时,我们可能需要启动一个后台进程,它可以在不阻塞主程序退出的情况下运行。要标记守护进程,可以添加第三个参数daemon,设置为True。默认值为False,不充当守护进程。示例如下:multiprocessing.current_process().name,"start")time.sleep(2)print(multiprocessing.current_process().name,"end")if__name__=="__main__":p1=multiprocessing.Process(name='p1',target=worker)p2=multiprocessing.Process(name='p2',target=worker2,daemon=True)p3=multiprocessing.Process(name='p3',target=worker2,daemon=True)p1.start()p2.start()p3.start()运行后,效果如下:p2和p3是daemon进程,而p1不是,所以执行1秒后,主程序退出,p2p3的内容不是打印。但是直到执行完毕,它还在执行中。join()同样,如果你希望强制等待守护进程结束,你可以添加join()函数。还是上面的代码,例子如下:():print(multiprocessing.current_process().name,"start")time.sleep(2)print(multiprocessing.current_process().name,"end")if__name__=="__main__":p1=multiprocessing.Process(name='p1',target=worker)p2=multiprocessing.Process(name='p2',target=worker2,daemon=True)p3=multiprocessing.Process(name='p3',target=worker2,daemon=True)p1.start()p2.start()p3.start()p1.join()p2.join()p3.join()运行后,结果和设置进程名一样,所以不会显示在这里。与守护程序代码的唯一区别是最后三行join()函数代码。当然,跟线程一样,你可以传入一个time给join()函数。过了这个时间,主线程就不会再等待了。强行结束进程如果一个进程挂了或者不小心进入了死锁状态,那么这个时候我们往往会强行结束进程。在进程对象上调用terminate()会终止子进程。示例如下:importmultiprocessingimporttimedefworker():print(multiprocessing.current_process().name,"start")time.sleep(5)print(multiprocessing.current_process().name,"end")if__name__=="__main__":p1=multiprocessing.Process(name='p1',target=worker)p1.start()print("它还在运行吗",p1.is_alive())p1.terminate()print("它还在运行吗",p1.is_alive())p1.join()print("Isitstillrunning",p1.is_alive())运行后输出如下:终止进程后,使用join()函数等待退出的过程。允许进程管理代码有足够的时间来更新对象的状态以反映进程已终止。进程退出状态代码当进程退出时,可以通过exitcode属性访问生成的状态代码。下表是其状态码取值范围及含义:测试如下:importmultiprocessingimporttimedefworker():print(multiprocessing.current_process().name,"start")time.sleep(5)print(multiprocessing.current_process().name,"end")if__name__=="__main__":p1=multiprocessing.Process(name='p1',target=worker)p2=multiprocessing.Process(name='p2',target=worker)p1.start()p2.start()print("它还在运行吗",p1.is_alive())p1.terminate()print("它还在运行吗",p1.is_alive())print(p1.exitcode)p1.join()print("Isitstillrunning",p1.is_alive())print(p1.exitcode)time.sleep(5.5)print(p2.exitcode)运行后效果如下:可以看到强制退出进程的错误代码为负数,正常退出进程的错误代码为0。在调试并发问题时,访问multiprocessing提供的对象的内部状态会很有用。在实际项目中,我们可以使用一个方便的模块级函数启用日志记录,该函数使用日志记录创建一个记录器对象,并添加一个处理程序,使日志消息发送到标准错误通道。下面是一个例子:,target=worker)p1.start()p1.join()运行后,效果如下:派生进程和线程一样,我们可以自定义进程,而不是只传入一个函数来创建进程.创建进程的方法是从进程类派生。示例如下:importmultiprocessingclassWorkerProcess(multiprocessing.Process):defrun(self):print(self.name)returnif__name__=="__main__":foriinrange(5):p=WorkerProcess()p.start()p.join()运行后效果如下:multiprocessing库的进程知识和threading一样长,因为这篇文章的内容够长,剩下的知识会在下一篇博文中讲解。
