码迷,mamicode.com
首页 > 编程语言 > 详细

线程锁与其他用法

时间:2019-08-23 22:38:22      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:虚拟   实现   线程锁   需要   类型   计算机   调用   gil   并发   

 

一、死锁与递归锁

死锁的现象归根在于函数功能中含有连续锁,并且,各个锁的加锁与解锁时存在一定的时间差。当多个此类函数出现加锁的次序不一致时,当不同进程/线程调用这些函数,可能因为首次抢得锁的进程/线程释放锁的次序不同,导致其他进程/线程抢得锁的样式也不一致,无法在一个功能函数中连续使用,出现死锁。

优点:针对性加锁,每把锁赋予不同的权限,便于把控函数进程。

缺点:不同功能函数可能因为功能逻辑需要,加锁次序不同,但是在线程在调用多个函数时,就会可能出现死锁现象,注意点较多,无法完成对应加锁解锁,降低的使用效率与准确度。

递归锁:

为了解决死锁现象,引入了递归锁。

递归锁符号: from threading import RLock

lock_A=lock_B=RLock()

大致原理是,初始化时,将所有的锁同等看待。不计锁的类型只计加锁解锁的次数。初始化时,默认加锁次数为0,函数每经过一次加锁,计数增加1,每解一次锁,技术减去1。当加锁次数回归到0时,说明函数处于可被多个进程/线程争抢调用阶段。

优势:将所有的锁的一视同仁,不必对应加解同类型的锁,只需考虑加锁次数。在进程/线程调用函数时,方便检测与使用。

缺点:但是锁的针对性较差。无法有针对性的加锁。

二、GIL全局锁

因为同一线程总的数据是共享的,为了保证数据的安全性与稳定,python在早期开发的时候,因为当时的CPU只有一核,便针对全线程加锁,此锁成为GIL全局锁.随着后续科技发展,出现多核处理器,但是python全局锁保留下来(由于更改语言的耗费太大),由此导致了影响下面的处理数据的差异。这种差异针对cpython(python为解释性语言,即地层基于C语言识别字节码的解释器)较为明显,其他的jpython与pypy等等不受此影响。 

cpython解释路径:

大致路径: 文件——编译器(c语言识别的字节码)——虚拟机(字节码转化成机器码)——CPU。

由此cpython限定,同一时间单核只能允许一个线程/进程解释器。

加全局锁的优点:保证了cpython解释器的资源安全性。

缺点:单个进程的多线程不能利用多核资源,理论上降低了CPU的使用效率。

cpython运行不同类型阻塞出现了自身的特点:

1、I/O阻塞

单个进程的多个线程并发的运行速度并不比多进程并发慢。

原因在与单核CPu在同进程的多线程运行遇到IO阻塞,便会在多线程之间进行切换。而多个CPU运行多进程(并发)每个进程遇到IO阻塞,处于等待状态,同样会相互切换,设想当全部进程处于阻塞状态时,所有的CPU同样均会处于停滞状态。另外,线程的开启速度要快于进程,线程的开启耗费资源要低于进程。由以上两点,决定单进程的线程(单核)并行与多进程并发(多核)相比,稍具优势。可以简单理解为,阻塞来自外部,再好的计算机同样需要等待外部处理。

开启多线程运行速度要高于多进程。

2、计算密集型阻塞

计算密集型阻塞出现的原因在于CPU运算并未出现代码源运行终断,只是在与CPU运行时间过长,会在多个计算过程中进行切换。

在此过程中,单进程中多线程并行,与多进程并发的区别在于单核CPU运算要在不同线程之间来会切换,就是一个CPU同时处理多个运算,资源要在多个线程之间分配。而针对多核CPU,每个CPU处理单个运算,并不用相互切换,此时计算机合理分配了CPU资源,CPU会专注进行单个运算。时间较短。 

3、GIL全局锁与lock锁的区别

相同点:都是同种锁,互斥锁

不同点:

1)GIL全局锁,保护解释器内部资源数据安全。

2)GIL上锁与解锁无需手动。

3)自己代码中定义的互斥锁保护进程中的资源数据安全。

4)自己定义的互斥锁,需要自己手动加锁解锁。 

三、信息量 

信息量允许多个线程/进程共抢CPU资源。

符号及使用: from threading import Semaphore,用法与lock相似。

首先初始化,规定单次最大处理量 sem=Semaphore(5).

其次在被执行函数内部语句加锁,sem.acquire()

最后,在执行语句之后,解锁sem.release()。

大致作用是,规定最大同时可以运行的线程数量,假如需要处理的线程数量较多,就会类似银行业务窗口实现空位一次填补。

四、基于多线程的socket通信

基于多线程的socket与之前多链接(服务器双重while循环)基于socket通信的异同:

前者主要要解决一个如何在同一server端下开启多线程的问题。即分清主线程的完成的任务与子线程完成的任务。

服务端:

主线程的任务要完成,初始化,绑定地址(服务器只能绑定一个地址),完成循环监听,响应连接并开启子线程的任务,其中,作为服务器,开启子进程的数量越大越好,任务较为关键。(若要限定,可以考虑for循环,若无限定,采用while循环)

子线程主要完成循环收发消息,实现通信等任务,即实现线程运行中调用函数。调用函数根据函数需求,确定传参的数量与类型。

客户端:与普通socket通信功能没有太大区别。

 

 

  

 

线程锁与其他用法

标签:虚拟   实现   线程锁   需要   类型   计算机   调用   gil   并发   

原文地址:https://www.cnblogs.com/fuzhang/p/11402470.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!