1.互斥锁:
原理:将并行变成串行
精髓:局部串行,只针对共享数据修改
保护不同的数据就应该用不用的锁
from threading import Thread, Lock
import time n = 100 def task():
global n
mutex.acquire() # 效率低了 但是数据安全了
temp = n
time.sleep(0.1) # 100个线程 都拿到了100 所以就是 100个线程100-1
n = temp - 1
mutex.release() if __name__ == '__main__':
mutex = Lock()
t_l = []
for i in range(100):
t = Thread(target=task)
t_l.append(t)
t.start() for t in t_l:
t.join() print('主', n)
"""
主 99 原因: 100个线程 都拿到了100 所以就是 100个线程100-1 数据不安全 效率高但是不安全
要将并行改为串行
"""
"""
主 0 原因:效率低了 但是数据安全了
"""
2.GIL: global interpreter lock
python3 test.py
ps aux | grep test # linux
tasklist | findstr python # windows python.exe 运行python 会有几步:
1.会有一个进程,进程内存空间 python解释器的代码先加载到内存空间
2.test.py 内容加载到内存
3.解释执行;代码交给了python解释器
线程干活指向了python代码 python代码当作参数传给了解释器
线程拿到解释器的代码,拿着python代码当作参数,执行
垃圾回收线程运行解释器的代码
垃圾回收线程和某一个线程冲突了,数据不安全,
开多个进程,GIL就没影响了, cpython解释器垃圾回收线程定期启动一个
GIL:互斥锁,保证数据的安全 对CPython解释器,同一时间只有一个线程运行
GIL.acquire() 这样垃圾线程和线程就不会冲突了,这样回收机制就变得安全了
GIL.release()
python解释器,多线程有GIL存在,保证了一个进程下面多个线程的执行是一个一个执行的 有GIL与自动的锁的工作原理:
总结:
1.GIL 一个进程内的多个线程同一时间只能运行一个线程,垃圾回收线程是安全的
2.针对不同的数据,就应该加不同的锁,解释器级别的GIL锁,只能保护解释器级别的数据,
不能保护自己的数据,针对自己的共享数据还要加锁; 线程首先抢的是;GIL锁,之后才是mutex
官网:
结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势 GIL的存在:同一时刻,只能有一个线程在运行
多核,多进程,但进程开销大,多线程,又不能用多核 ? cpu干计算的,多个cpu
1.如果是干计算的操作,多核省时间
2.如果干IO阻塞型操作,多核没用 程序运行:都会干计算和IO操作 四个任务:
1.1个核:开多线程 ,因为多进程能用上多核
2.多核:
计算密集型:用多进程,用多核,eg:金融行业的,计算比较多,虽然多进程开销大,但多核,保证了计算快
IO密集型:用多线程,同一时间只能用一个核,1个核一个进程,多线程就在一个核上来回切和四个核来回切是一样的 现在写的软件:
网络打交道,网络的IO
IO密集型,用多线程
"""
计算密集型应该用: 多进程 效率高
"""
from multiprocessing import Process
from threading import Thread
import os,time def work():
res=0
for i in range(100000000):
res*=i if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为8核
start=time.time()
for i in range(8):
# p=Process(target=work) #耗时8s多
p=Thread(target=work) #耗时37s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start)) """
IO密集型:多线程 效率高
"""
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
time.sleep(2)
print('===>') if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为8核
start=time.time()
for i in range(400):
# p=Process(target=work) #耗时8s多,大部分时间耗费在创建进程上
p=Thread(target=work) #耗时2s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
3.死锁:
你拿着我的锁,我拿着你的锁 互斥锁:Lock()
互斥锁只能acquire一次 递归锁:RLock()
可以连续acquire多次,每acquire一次计数器+1,
只有计数为0时,才能被抢到acquire
from threading import Thread,Lock
import time mutexA=Lock()
mutexB=Lock() class MyThread(Thread):
def run(self):
self.f1()
self.f2() def f1(self):
mutexA.acquire()
print('%s 拿到了A锁' %self.name) mutexB.acquire()
print('%s 拿到了B锁' %self.name)
mutexB.release() mutexA.release() def f2(self):
mutexB.acquire()
print('%s 拿到了B锁' % self.name)
time.sleep(0.1) mutexA.acquire()
print('%s 拿到了A锁' % self.name)
mutexA.release() mutexB.release() if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
"""
Thread-1 拿到了A锁 # 死锁了 卡住了
Thread-1 拿到了B锁
Thread-1 拿到了B锁
Thread-2 拿到了A锁
"""
# 互斥锁只能acquire一次
# from threading import Thread,Lock
#
# mutexA=Lock()
#
# mutexA.acquire()
# mutexA.release() # 递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire
from threading import Thread,RLock
import time mutexB=mutexA=RLock() class MyThread(Thread):
def run(self):
self.f1()
self.f2() def f1(self):
mutexA.acquire()
print('%s 拿到了A锁' %self.name) mutexB.acquire()
print('%s 拿到了B锁' %self.name)
mutexB.release() mutexA.release() def f2(self):
mutexB.acquire()
print('%s 拿到了B锁' % self.name)
time.sleep(2) mutexA.acquire()
print('%s 拿到了A锁' % self.name)
mutexA.release() mutexB.release() if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
"""
Thread-1 拿到了A锁 # 解决了 死锁
Thread-1 拿到了B锁
Thread-1 拿到了B锁
Thread-1 拿到了A锁
Thread-2 拿到了A锁
Thread-2 拿到了B锁
Thread-2 拿到了B锁
Thread-2 拿到了A锁
Thread-4 拿到了A锁
Thread-4 拿到了B锁
Thread-5 拿到了A锁
Thread-5 拿到了B锁
Thread-5 拿到了B锁
Thread-5 拿到了A锁
Thread-7 拿到了A锁
Thread-7 拿到了B锁
Thread-7 拿到了B锁
Thread-7 拿到了A锁
Thread-9 拿到了A锁
Thread-9 拿到了B锁
Thread-9 拿到了B锁
Thread-9 拿到了A锁
Thread-3 拿到了A锁
Thread-3 拿到了B锁
Thread-3 拿到了B锁
Thread-3 拿到了A锁
Thread-6 拿到了A锁
Thread-6 拿到了B锁
Thread-6 拿到了B锁
Thread-6 拿到了A锁
Thread-10 拿到了A锁
Thread-10 拿到了B锁
Thread-10 拿到了B锁
Thread-10 拿到了A锁
Thread-8 拿到了A锁
Thread-8 拿到了B锁
Thread-8 拿到了B锁
Thread-8 拿到了A锁
Thread-4 拿到了B锁
Thread-4 拿到了A锁
"""
4.信号量
信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,
信号量同一时间可以有5个任务拿到锁去执行
信号量:同一时间有多个线程在进行
from threading import Thread,Semaphore,currentThread
import time,random sm=Semaphore(1) def task():
# sm.acquire()
# print('%s in' %currentThread().getName())
# sm.release()
with sm: # 类似于sm.acquire() # 同一时间可以来3个人,1个人,或者2个人
print('%s in' %currentThread().getName())
time.sleep(random.randint(1,3)) if __name__ == '__main__':
for i in range(10):
t=Thread(target=task)
t.start()
"""
Thread-1 in
Thread-2 in
Thread-3 in Thread-4 in Thread-6 in
Thread-5 in
Thread-7 in Thread-8 in
Thread-9 in Thread-10 in
"""
5.Event:
多个线程之间同步的,一个线程告诉另一些线程可以做其他的活了
event.wait()
event.wait(2)
event.set()
event.is_set()
event.clear()
from threading import Thread,Event
import time event=Event()
# event.wait() # 等 ...直到 set
# event.set() def student(name):
print('学生%s 正在听课' %name)
# event.wait() # 学生要等7秒 才能下课
event.wait(2) # 学生等2秒 直接下课了 print('学生%s 课间活动' %name) def teacher(name):
print('老师%s 正在授课' %name)
time.sleep(7)
event.set() if __name__ == '__main__':
stu1=Thread(target=student,args=('alex',))
stu2=Thread(target=student,args=('wxx',))
stu3=Thread(target=student,args=('yxx',))
t1=Thread(target=teacher,args=('egon',)) stu1.start()
stu2.start()
stu3.start()
t1.start() # ------------------
# 设置链接的超时时间
from threading import Thread,Event,currentThread
import time event=Event() def conn():
# print('%s is connecting'%currentThread().getName())
# event.wait()
# print('%s is connected'%currentThread().getName()) n=0
while not event.is_set():
if n == 3:
print('%s try too many times' %currentThread().getName())
return
print('%s try %s' %(currentThread().getName(),n))
event.wait(0.5)
n+=1 print('%s is connected' %currentThread().getName()) def check():
print('%s is checking' %currentThread().getName())
time.sleep(5)
event.set() if __name__ == '__main__':
for i in range(3):
t=Thread(target=conn)
t.start()
t=Thread(target=check)
t.start()
"""
Thread-1 try 0
Thread-2 try 0
Thread-3 try 0
Thread-4 is checking
Thread-3 try 1
Thread-2 try 1
Thread-1 try 1
Thread-3 try 2
Thread-1 try 2
Thread-2 try 2
Thread-3 try too many times
Thread-2 try too many times
Thread-1 try too many times
"""
6.定时器:Timer
t=Timer(5,task,args=('egon',))
t.start()
t.cancel()
from threading import Timer def task(name):
print('hello %s' %name) t=Timer(5,task,args=('egon',)) # 就是起了一个线程
t.start() # ----------------------
from threading import Timer
import random class Code:
def __init__(self):
self.make_cache() def make_cache(self,interval=10):
self.cache=self.make_code()
print(self.cache)
self.t=Timer(interval,self.make_cache)
self.t.start() def make_code(self,n=4):
res=''
for i in range(n):
s1=str(random.randint(0,9))
s2=chr(random.randint(65,90))
res+=random.choice([s1,s2])
return res def check(self):
while True:
code=input('请输入你的验证码>>: ').strip()
if code.upper() == self.cache:
print('验证码输入正确')
self.t.cancel()
break obj=Code()
obj.check()
并发编程 - 线程 - 1.互斥锁/2.GIL解释器锁/3.死锁与递归锁/4.信号量/5.Event事件/6.定时器的更多相关文章
-
[并发编程 - 多线程:信号量、死锁与递归锁、时间Event、定时器Timer、线程队列、GIL锁]
[并发编程 - 多线程:信号量.死锁与递归锁.时间Event.定时器Timer.线程队列.GIL锁] 信号量 信号量Semaphore:管理一个内置的计数器 每当调用acquire()时内置计数器-1 ...
-
10 并发编程-(线程)-GIL全局解释器锁&;死锁与递归锁
一.GIL全局解释器锁 1.引子 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势 首先需要明确的一点是GIL并不是Python的特性,它是在实现Pyt ...
-
并发编程-线程-死锁现象-GIL全局锁-线程池
一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...
-
并发编程(五)——GIL全局解释器锁、死锁现象与递归锁、信号量、Event事件、线程queue
GIL.死锁现象与递归锁.信号量.Event事件.线程queue 一.GIL全局解释器锁 1.什么是全局解释器锁 GIL本质就是一把互斥锁,相当于执行权限,每个进程内都会存在一把GIL,同一进程内的多 ...
-
Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
-
TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q
TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...
-
Java并发编程实战 03互斥锁 解决原子性问题
文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...
-
Python并发编程-线程锁
互斥锁-Lock #多线程中虽然有GIL,但是还是有可能产生数据不安全,故还需加锁 from threading import Lock, Thread #互斥锁 import time def ea ...
-
python并发编程之线程(二):死锁和递归锁&;信号量&;定时器&;线程queue&;事件evevt
一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...
随机推荐
-
EntityFrame Work 6 Code First 配置字段为varchar 类型
EntityFrame Work 6 配置字符串属性是否支持Unicode 内容 默认情况下,字符串为Unicode(SQLServer 中的nvarchar).您可以使用IsUnicode 方法指定 ...
-
Ubuntu 12.04设置豆沙绿
首先确保已安装dconf-editor sudo apt-get install dconf-tools 然后打开dconf-editor 找到:org – gnome -desktop – ...
-
MSSQL - 视图操作
查询语句(包含使用Where子句): string sql = @"SELECT TableName, TablePosition,TableSate, TabelType,OpenTime ...
-
VIM 第二天--快捷键
好吧,今天是重新学习vim的第二天,不得不说,收货丰厚. 先来勉励一下自己: 存活(目前状态) 感觉很好 感觉更好,更强,更快 吃用vim超能力 vimtutor练到lesson 7了,略微总结一下, ...
-
2.11 while循环的嵌套以及应用(难)
while循环嵌套 前面学习过if的嵌套了,想一想if嵌套是什么样子的? 类似if的嵌套,while嵌套就是:while里面还有while <1>while嵌套的格式 while 条件1: ...
-
PHP 程序员危机(转载)
感谢有这样的机会,能和大家一起来聊聊开发者的那些事儿. 其实程序员危机是一个真实存在的问题.也有人说是互联网行业的下滑或者互联网行业已过了风口等等.我在这儿主要谈的是 PHP 程序员的危机,而这种危机 ...
-
re正则匹配城市名
匹配城市名称,只要第一次出现之后的数据 import re a='巴州区白云县台公交乡公司对面区海蜃楼6楼' b=re.search(r'(^\w+?区)|(^\w+?县)|(^\w+?镇)',a). ...
-
MySQL系列详解十:MySQL多源复制演示-技术流ken
前言 多源复制即多主一从结构,多个主服务器端的数据都会同步到后端一个从服务器上面.至于为什么要做多源复制下面的总结很到位. 1.灾备作用:将各个库汇总在一起,就算是其他库都挂了(整个机房都无法连接了) ...
-
Jwt Token 安全策略使用 ECDSA 椭圆曲线加密算法签名/验证
椭圆曲线密码学(Elliptic curve cryptography),简称 ECC,是一种建立公开密钥加密的算法,也就是非对称加密,ECDH 与 ECDSA 是基于 ECC 的算法.类似的还有 R ...
-
MySQL事务隔离级别以及验证
事务的并发执行,容易出现的几个现象 -------------------------- 1.脏读 读未提交,一个事务读取了另外一个事务改写还没有提交的数据,如果另外一个 ...