多线程编程的相关介绍告一段落,今天开始介绍关于多进程编程的内容。
本文的主要内容有:
1、多线程与多进程的比较
2、通过os模块简单演示多进程
多线程与多进程的比较通过前面的文章,相信能够对多线程编程有一个相对完整、清晰的理解。在真正进入多进程编程的内容介绍之前,首先来比较一下,多线程和多进程,通过类比,希望能够对多进程有个更加全局性的认知,也加深一下对多线程内容的掌握。
接下来,将分别从执行效率、资源开销、编程复杂性及适用场景方面,对两者进行比较。
1、执行效率
通常来说,多线程的优点在于线程的切换相对轻量级,多线程复用同一个进程的内存资源,包括堆栈等,创建、销毁、切换上下文,相对开销较小。因此,在CPU密集型任务中,多线程的执行效率较高。
但是,在Python中,由于全局解释器锁(GIL)的存在,对于CPU密集型任务,多线程并不能实现真正的并行执行,可能会导致性能受限。反而是IO密集型任务,Python中的多线程更能利用IO等待时间,发挥并行的优势。
多进程中,每个进程有自己的内存空间和资源,能够实现真正的并行,特别是在多核CPU上,更加适用于CPU密集型任务。但是,进程的上下文切换,可能会导致效率的降低。
2、资源开销
线程之间,由于共享内存和资源,因此在频繁通信的场景中,线程资源的开销相对较小。但是,由于资源的共享,也引入了一致性和竞争问题,需要小心进行同步的管理。
多进程中,每个进程拥有独立的内存空间,进程间不会直接影响,安全性更高,但是,进程间通信的资源开销较大,且进程上下文切换也会导致更多的资源开销。
3、编程复杂性
多线程编程相对容易实现,代码结构也比较简洁。但是,由于共享内存和竞争条件,可能会引入复杂性,需要更多地考虑线程安全和同步的问题。
多进程中,每个进程相互独立,数据的隔离使得编程更加安全,减少了多线程中线程安全问题的复杂性。但是,跨进程的通信协作,也会引入新的复杂性。
4、适用场景
通常来说,多线程更适合IO密集型任务,以及大量的短时任务的并发场景,因为其上下文切换、创建、销毁资源开销较小。但是,Python中,GIL的存在,导致多线程不太适合CPU密集型任务。
多进程编程,特别适合CPU密集型任务,比如大数据处理、图像处理等。多进程能够充分利用多核CPU的优势,真正实现并行处理。但是,如果是大批量短时任务,涉及到频繁的进程创建、销毁、上下文切换,可能反而会导致执行效率的降低。
通过os模块简单演示多进程简单对比了多线程和多进程的各个维度下的优缺点,接下来,通过Python中的os模块,来简单演示一下多进程。
首先简单介绍一下os模块中,关于进程管理的常用方法:
1、os.fork()函数
创建子进程,调用该函数后,当前进程将被复制,整个进程的状态、堆栈数据、代码都会被复制到子进程中。
在父进程中,会返回子进程的PID,在子进程中会返回0。
2、os.exec*家族函数
用指定的程序替换当前进程的映像,比如os.execvp()、os.execv()等。执行完成后会返回到调用的程序中,当前进程被新的程序替换。
3、os.wait()
使当前进程挂起,直到一个子进程终止,返回值包含子进程的PID以及其退出状态。通常在父进程中调用,用于等待子进程结束,防止僵尸进程。
4、os.kill(pid, sig)
向指定PID的进程发送一个信号,可以用来终止或者控制进程的行为,相关的信号,可以通过signal模块查看:
5、os.getpid()和os.getppid()
分别用于获取当先进程的PID和当前进程的父进程的PID。
接下来,通过代码简单演示一下多进程的执行效果。
需要首先说明的是,os模块中的相关方法和组件,有些可能是基于Linux内核的调用。以下代码,在Linux或者mac可以正常运行,但是在Windows上可能会出现异常。
执行结果:
从执行结果可以看到:
1)从os.fork()这一行开始,后续的代码会同样在子进程中执行一遍,所以,以下的代码会执行两遍(主进程和子进程)。
2)主进程中通过os.wait()将等待子进程结束才继续向下执行。
3)os.execlp()的函数调用,导致主进程和子进程的映像都被替换为ls的执行了。所以,之后的代码不会被执行了。
总结本文通过对多线程和多进程的比较,一方面对多线程的内容做了个梳理总结,另一方面也对多进程的内容,做了一个全局性的引入。最后,通过os模块中相关进程管理的函数,简单演示了多进程。
以上就是本文的全部内容,感谢您的拨冗阅读。