企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## 线程理论知识 ### 什么是线程和多线程 * **线程:** 顾名思义,就是一条流水线工作的过程,而一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一条流水线。 进程只是用来把资源集中到一起,而线程才是cpu上的执行单位。 * **多线程:** 在一个进程中存在多个线程,多个线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。 ### 线程与进程的区别 1. 同一个进程内的多个线程共享该进程内的地址资源 2. 创建线程的开销要远小于创建进程的开销 创建一个进程,就是创建一个车间,涉及到申请空间,而且在该空间内建至少一条流水线 但创建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小 ### 线程与进程总结 1. **线程是计算机中能被CPU调度的最小单位** 2. **进程是计算机中资源分派的最小单位** 3. **每一个进程中至少有一个线程** * 多线程的特点 并发的、轻量级、数据不隔离 * 多进程的特点 并发的、操作比较笨重、数据完全隔离 ## 全局解释器锁GIL 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势 GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。 ### GIL与Lock 锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据,保护不同的数据就应该加不同的锁。 GIL 与Lock是两把锁,保护的数据不一样,前者是解释器级别的(当然保护的就是解释器级别的数据,比如垃圾回收的数据),后者是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事,只能用户自定义加锁处理,即Lock,如下图 ![enter description here](https://www.github.com/noah-luo/imags/raw/master/year/1551406460359.png) 分析: ~~~ 1、100个线程去抢GIL锁,即抢执行权限 2、肯定有一个线程先抢到GIL(如线程1),然后开始执行,一旦执行就会拿到lock.acquire() 3、极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL并开始运行 但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL 4、直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock 然后其他的线程再重复2 3 4的过程 ~~~ ### GIL与多线程 有了GIL的存在,同一时刻同一进程中只有一个线程被执行; 对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用 所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,然后在确定使用多线程还是多进程 * **多进程与多线程分析** 假设我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是: 方案一:多进程方案:开启四个进程 方案二:多线程方案:开启四个线程 * **单核情况下,分析结果:** 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜 如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜 * **多核情况下,分析结果:** 如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜 如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜 * **结论:** 多线程用于IO密集型,如socket,爬虫,web 多进程用于计算密集型,如金融分析