线程-Thread
进程是计算机中最小的资源分配单位,创建一个进程,操作系统需要向其分配一定的内存资源。所以进程对于操作系统来说还是有一定的负担。
线程是计算机中被CPU调度的最小单位,进程中的代码是由线程来完成的,每个进程可以有多个线程,但是至少要有一个线程。
线程是一个轻量级概念,它没有属于自己的资源。同一个进程中的所有的线程的资源是共享的。在Python中,一个进程中的多个线程无法并行,只能并发执行(Java,C++, C#等C语言中是可以的),主要是因为Python属于解释型语言,而Java,C语言属于编译型语言,Python中有独有的GIL(Global Interpreter Lock)全局解释器锁。
编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。而相对的,解释性语言编写的程序不进行预先编译,以文本方式存储程序代码。在发布程序时,看起来省了道编译工序。但是,在运行程序的时候,解释性语言必须先解释再运行。
线程和进程之间的区别主要在于:
占用的资源
调度的效率
资源是否共享
创建线程与创建进程的操作几乎相同:
为什么说线程是轻量级的概念呢?
结果显而易见的。
守护线程-setDaemon
守护线程是指在程序运行的时候在后台提供一种通用服务的线程。
守护线程的特性在进程中已经有过阐述,守护线程和守护进程其实差不多,但还是有些许差别:
从结果可以看出,守护线程并没有像进程一样,在主进程的代码结束之后便结束,反而等全部线程执行完毕之后再结束。因为在同一个进程中,多个线程的资源是共享的,因此守护线程的守护对象应该是全部线程而不是进程(进程的代码也要靠线程来执行)
当同时满足以下两个条件时,就会出现线程的安全问题①多个线程在操作共享的数据;②操作共享数据的线程代码有多条。
举例:
从一百到十万结果基本上都是0,但是当循环次数扩大到100万的时候,问题就开始显现了:
和进程修改共享数据的原理是一样的,多个线程多个代码对同一个共享数据进行修改,次数足够大时难免会出现同时操作的现象,自然而然就会产生数据的误差的问题。所以可以引入线程锁Lock的概念方法,进程锁Lock的原理为同一时刻只允许一个进程对数据进行修改,线程锁Lock的原理就是同一时刻只允许一个线程对数据进行修改。
这样就保护了数据安全,但是时间相对来说就长了很多很多
递归锁-RLock
递归锁的讲解需要引入“哲学家吃面问题”
所谓哲学家吃面问题就是每个哲学家必须要抢到叉子和面条才能够继续使程序继续进程,否则程序就会陷入死锁状态。也就是有两把锁,线程需要同时拿到两把才能够程序继续运行,否则一把锁被一个线程拿到,另一把锁被另一个线程拿到,这样两把锁就无法同时解锁,就进入死锁状态。
写一个死锁程序:
当eat1激活了noodle_lock之后,eat2的noodle_lock必须等到ea1释放才能激活。而eat1代码顺序为先面条后叉子,eat2代码顺序为先叉子后面条,所以在相同反应的情况下,哲学家2抢到面条的同时,哲学家3抢到了叉子,两个人同时抢到更靠近自己的东西,谁也不放手,表现为程序无法进行下去,也就是死锁现象。(为什么要用eat1和eat2两个方法,而不是只用eat1一个方法?是因为需要有一个偏向值,eat1更偏向面条,所以哲学家1和2更容易抢到面条,eat2更偏向叉子,所以哲学家3和4更容易抢到叉子。如果只用一个eat,那么表现为哲学家们按顺序吃面条(同步))
而且解锁的顺序也颇为讲究,采用后进先出法,具体表现为以下的图,第一道门开了锁进去,再开第二道锁再进去,那么出来的时候需要锁门,锁门就要先锁里面的门,不然都出来了还怎么锁里面的门呢?
为了解决死锁现象,threading模块中还提供了RLock递归锁的方法,
当多个线程同时抢多把锁的时候就会出现死锁的现象。其实递归锁也不是一个很好地解决方案,死锁现象的发生不是互斥锁的原因,而是程序猿/媛的逻辑出现了问题。
审核编辑:刘清
-
cpu
+关注
关注
68文章
10825浏览量
211146 -
计算机
+关注
关注
19文章
7419浏览量
87714 -
操作系统
+关注
关注
37文章
6738浏览量
123190 -
C语言
+关注
关注
180文章
7598浏览量
136186 -
线程
+关注
关注
0文章
504浏览量
19651
发布评论请先 登录
相关推荐
评论