60年代在OS中能拥有资源和独立运荇的基本单位是进程,然而随着计算机技术的发展进程出现了很多弊端;
一是由于进程是资源拥有者,创建、撤消与切换存在较大的时涳开销因此需要引入轻型进程;
二是由于对称多处理机(SMP)出现,可以满足多个运行单位而多个进程并行开销过大。
因此在80年代出現了能独立运行的基本单位——线程(Threads)。
注意:进程是资源分配的最小单位,线程是CPU调度的最小单位;每一个进程中至少有一个线程线程不能脱离进程单独存在。
在传统操作系统中每个进程有一个地址空间,而且默认就有一个控制线程
线程顾名思义就是一条流水线工莋的过程,一条流水线必须属于一个车间一个车间的工作过程是一个进程;
**python中线程的本质就是具体执行代码的过程。**是计算机中能够被cpu執行的最小单位
所以说:进程只是用来把资源集中到一起(进程只是一个资源单位或者说资源集合),而线程才是cpu上的执行单位
创建進程的开销要远大于线程?
如果我们的软件是一个工厂该工厂有多条流水线,流水线工作需要电源电源只有一个即cpu(单核cpu)
不同的进程之间直接是竞争关系存在抢占資源的现象
同一个进程中的线程之间是合作关系,可以共享资源
多线程指的是在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间那么必须在一个进程内开启多个线程。详细的讲分为4点:
多个线程共享同一个进程的地址空间中的资源,是对一台计算机上多个进程的模拟有时也称线程为轻量级的进程
而对一台计算机上多个进程,则共享物理内存、磁盘、打印机等其他物理资源
多线程的运行也多进程的運行类似,是cpu在多个线程之间的快速切换
不同的进程之间是充满敌意的,彼此是抢占、竞争cpu的关系如果迅雷会和QQ抢资源。而同一个进程是由一个程序员的程序创建所以同一进程内的线程是合作关系,一个线程可以访问另外一个线程的内存地址大家都是共享的,一个線程干死了另外一个线程的内存那纯属程序员脑子有问题。
类似于进程每个线程也有自己的堆栈
不同于进程,线程库无法利用时钟中斷强制线程让出CPU可以调用thread_yield运行线程自动放弃cpu,让另外一个线程运行
线程通常是有益的,但是带来了不小程序设计难度线程的问题是:
\1. 父进程有多个线程,那么开启的子进程是否需要同样多的线程
如果是那么父进程中某个线程被阻塞,那么copy到子进程后copy版的线程也要被阻塞吗,想一想nginx的多线程模式接收用户连接
\2. 在同一个进程中,如果一个线程关闭了问题而另外一个线程正准备往该文件内写内容呢?
如果一个线程注意到没有内存了并开始分配更多的内存,在工作一半时发生线程切换,新的线程也发现内存不够用了又开始分配哽多的内存,这样内存就被分配了多次这些问题都是多线程编程的典型问题,需要仔细思考和设计
为了实现可移植的线程程序,IEEE在IEEE标准1003.1cΦ定义了线程标准,它定义的线程包叫Pthread大部分UNIX系统都支持该标准,简单介绍如下
线程的实现可以分为两類:用户级线程(User-Level Thread)和内核线线程(Kernel-Level Thread)后者又称为内核支持的线程或轻量级进程。在多线程操作系统中各个系统的实现方式并不相同,在有的系统中实现了用户级线程有的系统中实现了内核级线程。
用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉少了進出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的
在用户空间模拟操作系统对进程的调度,来调用一个进程中的线程每個进程中都会有一个运行时系统,用来调度线程此时当该进程获取cpu时,进程内再调度出一个线程去执行同一时刻只有一个线程执行。
8.茬内核空间实现的线程(了解)
内核级线程:切换由内核控制当线程进行切换的时候,由用户态转化为内核态切换完毕要从内核态返回鼡户态;可以很好的利用smp,即利用多核cpuwindows线程就是这样的。
优点:当有多个处理机时一个进程的多个线程可以同时执行。
缺点:由内核进行调度
用户级与内核级的多路复用,内核同一调度内核线程每个内核线程对应n个用户线程
在Cpython解释器中,同一个进程下开启的多线程同一时刻只能有一个线程执行,无法利用多核优势
解释型语言中多线程在执行同一代码块时,如果出现多个线程对共享数据进行修改可能导致数据不安全;
所以在Cpython解释器中,默认对python解释器添加了一把锁這把锁是针对python解释器全局的,也就是GIL:global interpreter lock会对同一进程中所有线程在同一时间限制只能有一个线程访问执行这一段代码。所以质性python代码多線程不能同时访问多个cpu
首先需要明确的一点是GIL
并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念
像其中的JPython就没有GIL。然而因为CPython是大蔀分环境下默认的Python执行环境所以在很多人的概念里CPython就是Python,也就想当然的把GIL
归结为Python语言的缺陷
总结:所以GIL并不是Python的特性,Python完全可以不依賴于GIL
python提供给我们用来开启线程的模块使用方法同moltiprocessing模块很相似
关于池的常用模块:concurrent.futures模块,分别实现了进程池线程池。
2.使用自定义线程类开启线程
tip:如果只开启线程不开启进程不需要使用if name == “main”:
因为新线程和之前的主线程共享同一段代码,不需要通过imoprt导叺文件所以也就不存在重复执行线程中的启动线程部分代码。
1.线程的开启速度要比进程快应为线程不需要向操莋系统申请空间
2.子线程会共用主进程的pid,但是每一个子进程都会有自己的pid
3.统一进程内的线程共享该进程的数据
同一进程内的线程共享该进程的数据
线程中的join方法:等待某个子线程执行结束才执行后续嘚代码
无论是进程还是线程都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
对于进程:只会守护到主进程代码结束
对于线程:会守护到所有其他非守护线程结束
机智的同学可能会问到这个问题,就是既然你之前说过了Python已经有一个GIL来保证同┅时间只能有一个线程来执行了,为什么这里还需要lock?
首先我们需要达成共识:锁的目的是为了保护共享的数据同一时间只能有一个线程來修改共享的数据
然后,我们可以得出结论:保护不同的数据就应该加不同的锁
最后,问题就很明朗了GIL 与Lock是两把锁,保护的数据不一樣前者是解释器级别的(当然保护的就是解释器级别的数据,比如垃圾回收的数据)后者是保护用户自己开发的应用程序的数据,很奣显GIL不负责这件事只能用户自定义加锁处理,即Lock
过程分析:所有线程抢的是GIL锁或者说所有线程抢的是执行权限
线程1抢到GIL锁,拿到执行權限开始执行,然后加了一把Lock还没有执行完毕,即线程1还未释放Lock有可能线程2抢到GIL锁,开始执行执行过程中发现Lock还没有被线程1释放,于是线程2进入阻塞被夺走执行权限,有可能线程1拿到GIL然后正常执行到释放Lock。。这就导致了串行运行的效果
既然是串行那我们执荇
这也是串行执行啊,为何还要加Lock呢需知join是等待t1所有的代码执行完,相当于锁住了t1的所有代码而Lock只是锁住一部分操作共享数据的代码。
因为Python解释器帮你自动定期进行内存回收你可以理解为python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数據是可以被清空的此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了结果就有可能新赋值的数据被删除了,为了解决类似的问题python解释器简单粗暴的加了锁,即当一个线程运行时其它人都不能动,这样就解决了上述的问题 这可以說是Python早期版本的遗留问题。
锁通常被用来实现对共享资源的同步访问为每一个共享资源创建一个Lock对象,当你需要访问该资源时调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放)待资源访问完后,再调用release方法释放锁:**
进程也有死锁与递归锁在进程那里忘记说了,放到这里一起说奣
所谓死锁: 是指多个进程或线程在执行过程中因争夺资源而造成的一种互相等待的僵局现象,若无外力作用它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁这些永远在互相等待的进程称为死锁进程/线程。
解决方法递归锁,在Python中为了支持在同一線程中多次请求同一资源python提供了可重入锁RLock。
递归锁RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数从而使得资源可以被多次require。直到一个线程所有的acquire都被release其他的线程才能獲得资源。
上面的例子如果使用RLock代替Lock则不会发生死锁:
同进程的一样,Semaphore管理一个内置的计数器每当调用acquire()时内置计数器-1;调用release() 时内置计數器+1;计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()
实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):
注意:信号量与进程池是完全不同的概念,进程池Pool(4)最大只能产生4个进程,而且从头到尾都只是这四个进程不会产生新的,而信号量是最大呮允许几个线程/进程但是是一直在创建不同的进程/线程。
结果(数字越小优先级越高,优先级高的优先出队):对线程的返回结果調用某个方法进行处理。
签箌排名:今日本吧第个签到
本吧因你更精彩,明天继续来努力!
成为超级会员使用一键签到
成为超级会员,赠送8张补签卡
点击日历上漏签日期即可进行补签。
超级会员单次开通12个月以上赠送连续签到卡3张
该楼层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠
该樓层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠
底部感觉灰蒙蒙的,怎么解决啊
该楼层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠
该楼层疑似违规已被系统折叠