04:全局解释器锁(GIL)
1 全局解释器锁(GIL)

0 pypy(没有全局解释器锁) cpython(99.999999%)
-pypy python好多模块用不了,
1 全局解释器锁,GIL锁(cpython解释器的问题)
-当年python设计的时候,还是单核,没有多核的概念
-python需要做垃圾回收(gc)
-垃圾回收线程,进行垃圾回收
-设计了一个大锁(GIL锁),只有拿到这把锁的线程,才能执行
-同一时刻,在一个进程中,可以开多个线程,但是只能有一条线程在执行
-不能利用多核优势
只针对与cpython解释器(其他解释器,包括其他语言不这样)
2 如果是计算密集型:要开进程
3 如果是io密集型:要开线程
2 开启线程的两种方式
from threading import Thread
import time
#
# def task():
# time.sleep(1)
# print('我是子线程')
#
#
# if __name__ == '__main__':
# t=Thread(target=task)
# t.start()
# print('我是主线程')
#
#
###第二种方式
class MyThread(Thread):
def __init__(self,a):
self.a=a
super().__init__()
def run(self):
time.sleep(1)
print('我是子线程',self.a)
if __name__ == '__main__':
t=MyThread('aaaaa')
t.start()
print('我是主线程')
3 多线程与多进程比较

3.1 pid比较
3.2 开启速度比较
#开线程消耗的资源,耗费的时间远远小于开进程
from threading import Thread
import time
import os
from multiprocessing import Process
def task():
time.sleep(0.1)
print('我是子线程')
if __name__ == '__main__':
####线程
# ctime=time.time()
# t=Thread(target=task)
# t.start()
# t.join() # 等待子线程执行完成主线程再执行
# print('我是主线程')
# print(time.time()-ctime)
##进程
ctime=time.time()
t=Process(target=task)
t.start()
t.join() # 等待子线程执行完成主线程再执行
print('我是主线程')
print(time.time()-ctime)
3.3 内存数据的共享问题
##线程间数据共享
from threading import Thread
import time
import os
from multiprocessing import Process
def task():
global n
n=10
print(n)
if __name__ == '__main__':
####线程
n=100
t=Thread(target=task)
t.start()
t.join() # 等待子线程执行完成主线程再执行
print('我是主线程')
print(n)
4 Thread类的其他方法
from threading import Thread
import threading
import time
def task():
# time.sleep(0.01)
#在子线程中执行
# res = threading.currentThread()
# print(res)
res=threading.get_ident()
print('子线程:',res)
print('我是子线程')
if __name__ == '__main__':
t=Thread(target=task)
t1=Thread(target=task)
t.start()
t1.start()
# print(t.is_alive()) #看线程是否存活
#
# print(t.getName() ) # 获取线程的名字
# t.setName('lqz') # 设置线程民资
# print(t.getName() )
#
#
# print('主线程')
# time.sleep(0.02)
# print(t.is_alive())
# 主线程中执行,返回当前线程对象
# res=threading.currentThread()
# print(res)
# 返回当前进程中正在运行的子线程对象列表
# res=threading.enumerate()
# print(res)
# 返回当前正在运行的线程个数
# res=threading.activeCount()
# print(res)
# 线程id号
res=threading.get_ident()
print('主线程:',res) '''
t.is_alive()
t.getName()
t.setName('lqz') threading:模块下的一些方法
res=threading.currentThread()
res=threading.enumerate()
res=threading.activeCount()
res=threading.get_ident()
'''
5 join方法

等待子线程执行结束
from threading import Thread
import time
def task():
time.sleep(2)
print('我是子线程')
if __name__ == '__main__':
ll=[]
for i in range(1000):
t=Thread(target=task)
t.start()
ll.append(t)
for i in ll:
i.join()
# 主线程等待子线程执行完再执行
print('我是主线程,子线程全都执行完了')
6 守护线程
from threading import Thread
import time
def task():
time.sleep(2)
print('我是子线程')
if __name__ == '__main__':
t=Thread(target=task)
t.setDaemon(True) # 如果主线程执行结束,子线程也结束(不执行了)
t.start()
#只要主线程执行结束,子线程也结束
print('主线程执行结束')
7 同步锁(互斥锁)

## 多个线程操作同一个数据(变量),会出现并发安全的问题
# from threading import Thread,Lock
# import time
# import random
# def task():
# global n
#
#
# ### 临界区(加锁)
# time.sleep(random.random())
# temp=n
# time.sleep(random.random())
# temp=temp-1
# n=temp
#
# ##模拟不出来,因为太快了,没有cup的切换(io,时间片到了),模拟io,让cpu切换
#
# # n-=1
#
#
# if __name__ == '__main__':
# n=10
# ll=[]
# for i in range(10):
# t=Thread(target=task)
# t.start()
# ll.append(t)
#
# for i in ll:
# i.join()
#
#
# print(n) ###出现了并发安全的问题,加锁解决 from threading import Thread,Lock
import time
import random
def task_lock(lock):
global n ### 临界区(加锁)
with lock:
time.sleep(random.random())
temp=n
time.sleep(random.random())
temp=temp-1
n=temp ##模拟不出来,因为太快了,没有cup的切换(io,时间片到了),模拟io,让cpu切换 # n-=1 def task_no_lock(): global n
time.sleep(random.random())
temp=n
time.sleep(random.random())
temp=temp-1
n=temp if __name__ == '__main__':
n=10
lock=Lock()
ll=[]
for i in range(10):
# t=Thread(target=task_lock,args=[lock,])
t=Thread(target=task_no_lock,args=[lock,])
t.start()
ll.append(t)
t.join() # for i in ll:
# i.join() print(n) '''
互斥锁和join的区别
如果使用互斥锁:只锁临界区,只有临界区是串行,其他地方还是并发的
如果使用join,整个过程全变成串行执行 '''
8 信号量
### 信号量可以理解为多把锁,同时允许多个线程来更改数据 from threading import Thread,Semaphore import time
import random
def task(sm,i):
sm.acquire()
print('%s:这个人在上厕所'%i)
time.sleep(random.random())
print('%s:这个人拉完了'%i)
sm.release() sm=Semaphore(5)
for i in range(40):
t=Thread(target=task,args=[sm,i])
t.start()
9 Event事件

Event事件:
一些线程需要等到其他线程执行完成之后才能执行,类似于发射信号
比如一个线程等待另一个线程执行结束再继续执行 # 一些线程需要等到其他线程执行完成之后才能执行,类似于发射信号
# 比如一个线程等待另一个线程执行结束再继续执行 from threading import Thread, Event import time
import random def girl(event):
print('赵丽颖现在在结婚状态')
time.sleep(1)
# 离婚了,发送信号
print('赵丽颖离婚了')
event.set() # 发送一个信号 def boy(i, event):
print('屌丝%s:在等赵丽颖的离婚信号'%i)
event.wait() # 收不到信号之前,一直卡在这
print('屌丝%s号,收到了离婚信号,开始追' % i) event = Event()
t = Thread(target=girl, args=[event, ])
t.start() for i in range(10):
t1 = Thread(target=boy, args=[i, event])
t1.start() ## 写两条线程,一条线程读一个文件的头2分之一,另一个线程读这个文件的后2分之一,但是必须第一个线程读完,发送信号后,第二个线程才能读
总结
1 GIL锁:全局解释器锁,在解释器之上的一把大锁,线程必须获得这把锁,才能执行,只针对与cpython解释器
2 GIL和线程锁有什么区别?有了GIL锁,为什么还要线程锁?
-本身GIL和线程锁,都是线程级别的锁,GIL是内置的,解释器里的
-线程锁:开发者定义的
3 多核cpu:
如果是计算密集型:开进程
io密集型:开线程 4 开启线程的两种方式(对比进程)
5 进程和线程的比较
-进程id比较
-开启效率的比较
-共享变量 6 Thread类的其他方法,threading模块下的其他方法 7 线程join(等待子线程执行完成)
8 守护线程(如果主线程执行完成,子线程也结束)
9 互斥锁,同步锁:为了保证并发情况下数据安全,把对数据的操作过程变成串行,牺牲了效率,保证了数据安全
10 信号量,Event
04:全局解释器锁(GIL)的更多相关文章
- python 线程队列、线程池、全局解释器锁GIL
一.线程队列 队列特性:取一个值少一个,只能取一次,没有值的时候会阻塞,队列满了,也会阻塞 queue队列 :使用import queue,用法与进程Queue一样 queue is especial ...
- 全局解释器锁GIL
我们使用高并发,一次是创建1万个线程去修改一个数并打印结果看现象: from threading import Thread import os def func(args): global n n ...
- 全局解释器锁GIL & 线程锁
1.GIL锁(Global Interpreter Lock) Python代码的执行由Python虚拟机(也叫解释器主循环)来控制.Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行 ...
- python 什么是全局解释器锁GIL
什么是全局解释器锁GIL Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在 ...
- 并发编程——全局解释器锁GIL
1.全局解释器锁GIL GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全). 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行 同一时刻同一个进程内多个线 ...
- 21.线程,全局解释器锁(GIL)
import time from threading import Thread from multiprocessing import Process #计数的方式消耗系统资源 def two_hu ...
- Python全局解释器锁 -- GIL
首先强调背景: 1.GIL是什么?GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定. 2.每个CPU在同一时间只能 ...
- python 多线程编程之使用进程和全局解释器锁GIL
本文主要介绍如何在python中使用线程. 全局解释器锁: python代码的执行是由python虚拟机(又名解释器主循环)进行控制的.python中,主循环中同时只能有一个控制线程在执行,就像单核C ...
- Python核心技术与实战——十九|一起看看Python全局解释器锁GIL
我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...
- Python如何规避全局解释器锁(GIL)带来的限制
编程语言分类概念介绍(编译型语言.解释型语言.静态类型语言.动态类型语言概念与区别) https://www.cnblogs.com/zhoug2020/p/5972262.html Python解释 ...
随机推荐
- MySQL|一文解决主库已有数据的主从复制
主从复制配置方案和实际的场景有很多,在之前配置了主从库都是全新的配置方案 在这一篇会配置主库存在数据,然后配置主从复制 开始之前,先分享一套MySQL教程,小白入门或者学习巩固都可以看 MySQL基础 ...
- C#中的partial关键字
这节讲一下partial(局部的,部分的)关键字,初学者可能没有接触过这个关键字,但是只要你写过winform或者WPF应用程序的话,那你肯定被动用过这个关键字.首先介绍一下这个关键字的作用,它用作定 ...
- OO随笔之和蔼的第四单元——UML系列
本单元的OO作业相比以前的,实在可以以和蔼来形容.但是和蔼并不意味着什么都不做,这单元的两次作业,特点在于每种查询难度不大,但是有很多需要商榷的细节点和查询种类比较多.由于UML图和java8之间,存 ...
- [DB] Spark SQL
概述 基于Spark,兼容Hive 集成在Spark中,不需单独安装 提供统一的数据访问方式 结构化的数据类型:JDBC.JSON.Hive.Parquet(Saprk SQL 默认数据源) 支持标准 ...
- Linux_日志管理理论概述
一.日志系统 1.kernel -->物理终端(/dev/console) --> /var/log/dmesg(系统启动时信息(包括错误信息)记录到该文件) 或者:# dmesg 或 # ...
- (全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系?
(全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系? 产品经理马忠信关注 22015.08.30 13:59:20字数 2,660阅读 52,661 今天我给大家来讲讲这几个咱们经常打交道的词到 ...
- 064.Python开发虚拟环境
在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题:亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难.此时,我们需要对于不同的工程使用不同 ...
- 1.1Ubuntu安装
在虚拟机中安装 Ubuntu 步骤 安装前的准备和基本安装 设置语言环境 安装常用软件 1. 安装前的准备和基本安装 1.1 安装前的准备 访问 http://cn.ubuntu.com/downlo ...
- 为何使用thrift-rpc与http的选择
在工作中偶然看到公司旧架构在loaclserver中使用的是thrift,遂记录一下 thrif作为一种rpc框架 接口描述语言和二进制通信协议,至于为何使用thrift 其问题本质是为何在已有htt ...
- unity UGUI填坑 之 HorizontalLayoutGroup 和 ContentSizeFitter配合使用
今天在项目中遇到一个问题,我们的ui过来找我,问为什么Content里的Item显示的不完全 花了半个小时看了一下,发现个小小的坑,记录一下 这些属性是用来实现,Content下的Item的偏移和间隔 ...
