'''
定义:
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL
exists, other features have grown to depend on the guarantees that it enforces.)
'''
结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

 前言: 

- GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全)。
- 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行
- 同一时刻同一个进程内多个线程无法实现并行,但是可以实现并发

  一.GIL全局解释器 垃圾回收机制:

- 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿
- 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器
没有GIL全局解释器锁 他只是对线程加锁 不是对数据
运行垃圾回收机制:引用计数 1,必须先拿到python 解释器---> 2.python 进程下的多个线程是并发。若此时你想创建一个 a = 1 cpu运行速度是非常快的
那么就会引发 其他线程垃圾回收机制扫描把我刚创建的内存清理掉 所以必须设置GIL全局解释器锁
也就意味着在Cpython解释器上有一把GIL全局解释器锁

 二. 

1.python中的多线程到底有没有用?
  一、数据密集型
  二、IO密集型
#### 1.python中的多线程到底有没有用?

单核情况下:四个任务

多核情况下:四个任务

计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快

IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好
一、数据密集型
def task():
res = 0
for i in range(100000000):
res = res*i if __name__ == '__main__':
print(os.cpu_count()) #本机内核
p_list=[]
start_time= time.time()
for i in range(4):
p = Process(target=task) # 进程运行时间为10.636553287506104
# p = Thread(target= task) # 线程运行时间为19.97660756111145
p.start()
p_list.append(p)
for p in p_list:
p.join()
end_time = time.time()
print('运行时间为%s'% (end_time-start_time))

  

""
二、IO密集型
def work():
time.sleep(3)
if __name__ == '__main__':
print(os.cpu_count())
start_time =time.time()
p_list=[]
for i in range(4):
# p = Process(target= work) # run is total_time7.271259546279907
p = Thread(target= work) # run is total_time3.002392053604126
p.start()
p_list.append(p)
for p in p_list:
p.join()
end_time =time.time()
print('run is total_time%s'%(end_time-start_time))

  三、全局锁与普通锁

  

对于不同的数据,要想保证安全,需要加不同的锁处理
GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
保证的是同一个进程下多个线程之间的安全

  

"""
from threading import Thread import os
import time
from threading import Lock
mutex = Lock()
num = 100
def task():
global num
mutex.acquire() #抢锁
temp = num
time.sleep(0.1)
num = temp-1
mutex.release() # 释放锁 开始一个 if __name__ == '__main__':
p_lsit=[]
for i in range(10): p = Thread(target=task)
p.start()
p_lsit.append(p)
for p in p_lsit:
p.join()
print(num) # 90 相当于10个线程同时去抢100票 必须要确保一个数据同时被10个进程同时抢 锁是起到保护作用 取完一个减一个

  四、.死锁与递归锁(了解)

自定义锁一次acquire必须对应一次release,不能连续acquire

递归锁可以连续的acquire,每acquire一次计数加一

import time
from threading import Thread,RLock mutexA = mutexB= RLock() # 递归锁RLock
class Mythread(Thread): def run(self):
self.fn1()
self.fn2() def fn1(self):
#设置锁
mutexA.acquire()
print('%s 抢到A锁了'%self.name)
mutexB.acquire()
print('%s 抢到B锁了'%self.name)
mutexB.release()
print('%s释放了B锁'%self.name)
mutexA.release()
print('%s释放了A锁'%self.name) def fn2(self):
mutexB.acquire()
print('%s 抢到A锁了' % self.name)
time.sleep(1)
mutexA.acquire()
print('%s 抢到B锁了' % self.name)
mutexA.release()
print('%s释放了B锁' % self.name)
mutexB.release()
print('%s释放了A锁' % self.name) if __name__ == '__main__':
for i in range(100):
t = Mythread()
t.start()

  

五.Event事件

一些线程需要等待另外一些线程运行完毕才能运行,类似于发射信号一样

from threading import Thread

from threading import Event

import time
event = Event() #造了一个绿灯
def light():
print('等红灯')
time.sleep(3)
event.set() # 解除阻塞并且给 event发了一个信号
print('绿灯亮了') def car(i):
print('%s灯红灯'%i)
event.wait()
print('%s绿灯了,加油门'%i) if __name__ == '__main__':
t = Thread(target=light)
t.start() p_list=[]
for i in range(5):
p = Thread(target=car,args=(i,))
p.start() # 等红灯
# 0灯红灯
# 1灯红灯
# 2灯红灯
# 3灯红灯
# 4灯红灯
# 绿灯亮了
# 0绿灯了,加油门
# 1绿灯了,加油门
# 3绿灯了,加油门
# 4绿灯了,加油门
# 2绿灯了,加油门#

  

六.信号量(了解)

自定义的互斥锁如果是一个厕所,那么信号量就相当于公共厕所,门口挂着多个厕所的钥匙。抢和释放跟互斥锁一致

普通互斥锁, 独立卫生间 所有人只有一把锁
信号量 ,公共卫生间 有多少个坑 就有多少把锁
"""
from threading import Thread
from threading import Semaphore #信号量
import time
import random
sm = Semaphore(5) #一个公共厕所造了5个坑 在厕所外放了5把锁 def task(name):
sm.acquire() # 释放信号锁 print('%s正在蹲坑'%name)
time.sleep(random.randint(1, 3))
sm.release() for i in range(20):
t = Thread(target= task,args=('%s伞兵'%i,))
t.start()

 

0伞兵正在蹲坑
1伞兵正在蹲坑
2伞兵正在蹲坑
3伞兵正在蹲坑
4伞兵正在蹲坑
此时5个人中 有一个人好了 同时释放了一把锁
5伞兵正在蹲坑
前面5个好了两个释放给 6,7
6伞兵正在蹲坑
7伞兵正在蹲坑 8伞兵正在蹲坑
9伞兵正在蹲坑
10伞兵正在蹲坑
11伞兵正在蹲坑 12伞兵正在蹲坑
13伞兵正在蹲坑
14伞兵正在蹲坑
15伞兵正在蹲坑 16伞兵正在蹲坑
17伞兵正在蹲坑
18伞兵正在蹲坑
19伞兵正在蹲坑

  

  

七.线程queue

同一个进程下的线程数据都是共享的为什么还要用queue?queue本身自带锁的功能,能够保证数据的安全

  

import queue

"""
1.普通q
2.堆栈。先进后出q
3.优先级q """
q = queue.Queue(3)
q.put(1)
q.put(2) q.put(3)
print(q.get())
print(q.get())
print(q.get()) # 取值
——————》》》
1
2
3 q = queue.LifoQueue(5)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
q.put(5) print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get()) # 先进后出 和堆栈一样
——————》》》

5
4
3
2
1

q = queue.PriorityQueue(3)
q.put(100,"q")
q.put(20,"t")
q.put(-1,'s') print(q.get())
print(q.get())
print(q.get()) # 优先级是按照数字从小到大排列的
————————》》》

-1
20
100

  

  

最新文章

  1. 使用iframe的优缺点,为什么少用iframe以及iframe和frame的区别。
  2. 【夯实PHP基础】PHP 面向对象
  3. TP5的图片上传
  4. Pyqt清空Win回收站
  5. [Outlook] outlook如何实现自动CC和BCC邮件发送
  6. 转<<C#集合Dictionary中按值的降序排列
  7. reduce的数目到底和哪些因素有关
  8. (转)SQL中的ISNULL函数介绍
  9. 日期格式化{0:yyyy-MM-dd HH:mm:ss.fff}和{0:yyyy-MM-dd hh:mm:ss.fff}的区别
  10. 关于iOS 5 Could not instantiate class named NSLayoutConstraint错误
  11. mac 隐藏 显示 文件
  12. Linq左关联 右关联 内关联
  13. HTML中padding和margin的区别和用法
  14. linux中开启snmp协议
  15. python自动化报告的输出
  16. python中使用rabbitmq消息中间件
  17. PHP 弹窗 源代码 css Jquery.js
  18. nodejs 剪切图像在上传,并保存到指定路径下(./public/img/' + req.session.token + '.jpg‘)
  19. java刚開始学习的人常见的问题
  20. News summary on C# and .NET

热门文章

  1. mysql TOP语句 语法
  2. Apache简介
  3. Java——对象转型
  4. php 抽象类适配器设计模式
  5. SpringCloud 教程 (四) docker部署spring cloud项目
  6. CSP-S2 Review: 模拟
  7. Ecipse代码调试
  8. 【洛谷P1443 马的遍历】
  9. 洛谷P4317 花(fa)神的数论题(数位dp解法)
  10. tar 打包文件