进程和线程(Process and Thread)
一个进程可以有多个线程,也可以有单个线程,但一个进程 至少有一个 线程,多进程和多线程的程序涉及到同步、数据共享的问题,编写起来要考虑的问题比较多。
多任务的实现方式一般有 3种:
- 多进程模式
- 多线程模式
- 多进程+多线程模式
多进程(multiprocessing)
Python的os
模块封装了常见的系统调用,比如fork()
系统调用,该系统调用是创建一个与原来进程几乎完全相同的进程,一个进程调用 fork()
函数后,系统先给新的进程分配资源,例如存储数据和代码空间,然后把原来的进程的所有值都复制到新的进程中,只有少数值与原来的进程值不同,相当于克隆了一个自己。子进程永远返回0,而父进程返回子进程的ID,子进程调用getppid()
拿到父进程的ID,而getpid()
是得到本身的进程ID。 Windows 没有fork
系统调用 。
|
|
multiprocessing
模块提供了Process
类代表一个进程对象
|
|
进程池(Pool)
如果需要启动大量的子进程,可以用进程池(Pool)的方式批量创建子进程。
|
|
子进程及进程间的通讯
|
|
进程间的通讯,在模块multiprocessing
模块提供了Queue
,Pipes
等方式交换数据。这个交换可以是读,也可以是写。
|
|
多线程
线程是操作系统直接支持的执行单元,Python的标准库提供两个模块:_thread
和 threading
,前者是低级模块,后者是高级模块,是对前者的封装。
启动一个线程就是把一个函数传入并创建Thread
实例(一个方法,创建出来),然后调用start()
开始执行:
|
|
加锁(Lock)
可能存在读脏数据的问题,两个线程同时更新一个变量,导致出现意想不到的结果,所以多线程的时候,必须加锁(写的时候)。
|
|
Python解释器设计时带有 GIL(Global Interpreter Lock),任何线程执行前,必须获得该锁,每100条字节码后,自动释放该锁,因而多线程无法利用多核。
ThreadLocal
解决多线程局部变量传递,调用的问题。
|
|
进程 vs. 线程
多任务情况下,通常是 Master-Worker 模式, Master负责分配任务,Worker负责执行任务,通常只有一个Master,多个Worker。
- 主进程是Master,其他进程是Worker(多进程 实现该模式),稳定性高,代价大
- 主线程是Master,其他线程是Worker(多线程 实现该模式),效率高,不稳定
计算密集型 vs. IO密集型
任务的类型分为这两类:
- 计算密集型:需要进行大量的计算,任务同时进行的数量应当等于CPU的核心数,需要高效率的代码,一般使用C
- IO密集型:CPU消耗少,涉及网络、磁盘IO的任务,最合适的语言是脚本语言,如Python
异步IO
充分利用OS的异步IO支持,可以实现单进程单线程模型执行多任务,被称为事件驱动模型,Python中,单线程的异步编程模型称为 协程。
分布式进程(Distributed Process)
Process可以分布到多台机器中,而Thread只能分布在同一台机器的多个CPU中
在Python中的multiprocessing
模块的子模块managers
支持把多进程分布到多台机器上。
|
|