Python工作在用户级别的线程上。
【线程】线程可以看成是一个完成特定任务的有序的指令流,并且可以通过操作系统来调度这些指令流。线程通常位于一个进程中,由一个程序计数器、一个堆栈、一组寄存器、一个标识符组成。这些线程是处理器可以分配的最小的执行单元。线程是可以共享内存并且互相通信的。但当多个线程之间开始共享内存,就无法保证线程的执行顺序,这可能导致程序的错误,或者执行给出错误的结果。
【线程的分类】
- 用户级线程:用户可以进行创建、执行、杀死的线程
- 内核级线程:操作系统级别的线程
【多线程】CPU可以同时运行多个线程来处理任务,从本质上来说CPU是利用一个能够在多个线程之间快速切换的单个内核来完成多线程的运行,只要切换的速度够快用户是没有感知的。本质上并不是同时运行的
【线程的优点】
- 线程能够有效提升I/O阻塞型程序的效率
- 与进程相比,线程占用的系统资源要小的多
- 线程之间能够共享资源方便通信
【线程的缺点】
- Python中有全局解释器锁GIL的限制;
- 虽然线程之间能够进行通信,但是容易导致程序出错,使用的时候必须小心
- 多线程之间切换的话计算代价很高,会导致程序的整体性能下降
【进程与多线程】
进程在本质上和线程非常相似,进程几乎能够完成线程能够完成的所有的事情。一个进程里面包含着一个主线程和多个子线程,每个线程都包含自己的堆栈、寄存器。如果需要的话可以将他们组成多线程。
【进程的特性】
一个进程通常包含:
- 进程ID,进程组ID,用户ID,组ID;
- 环境
- 工作目录
- 程序指令
- 寄存器
- 堆栈
- 文件描述
- 进程间的通信工具……
【进程的优点】
- 能够有效地利用多核处理器
- 在处理CPU密集型任务时比线程要好
- 可以通过多进程来避免全局解释器锁GIL的局限
- 崩溃的进程不会导致整个进行程序都崩溃
【进程的缺点】
- 进程之间没有资源共享
- 进程需要消耗更多的系统内存
【多进程】
Python中可以用多线程或者多进程的方式来运行代码以改进单线程方式的性能。单核的机器上可以通过多线程来提高处理能力,但目前多核理器已经普遍,可以通过多进程来发挥机器价值。
Python的进程处理模块multiprocessing,可以有效地处理机器上的所有处理器,这有助于在处理CPU密集型任务时获得更高的性能。Python的multiprocessing模块可以查看当前机器上CPU的核心数量:
Import multiprocessing
print(multiprocessing.cpu_count())
【Python的局限性】
Python全局解释器锁GIL存在一定的局限性。GIL本质上是一个互斥锁,可以防止多个线程同时执行Python代码,它是一个只能有一个线程保持的锁,如果想要一个线程去执行代码,在他执行代码之前必须先获得这个锁,(这样做可以保证在该线程被执行时没有别的线程可以执行代码,一定程度上避免了线程之间的冲突)。
多个线程被GIL阻塞的情况如下,每个线程必须等待获取GIL才能进下一步的运行,然后再释放GIL,线程之间采用的方式是随机循环的方式,一次并不能控制是哪个线程先得到GIL。虽然有些难理解,但是这样做确实保证了多线程之间的内存安全。
【Python使用多线程和多进程的实例】
# I/O密集型的任务的适合使用多线程(多线程下载文件)
import threading
def executeThread(i):
pass
def exec():
treads= []
for i in range(10):
thread = threading.Tread(target = executeThread, arg = (i, ))
threads,append(thread)
thread,start()
for i in threads:
i.join()
if __name__== ‘__main__’
exec()
# CPU密集型的任务适合使用多进程(多进程顺序运算)
import multiprocessing import pool
def executePro:
pass
if __name__== ‘__main__’
pool = Pool(processes = 4)
pool.map_async(executeProc, range(1000000))
pool.close()
pool.join()