一、GIL:全局解释器锁  

  1 、GIL:全局解释器锁

GIL本质就是一把互斥锁,是夹在解释器身上的,

同一个进程内的所有线程都需要先抢到GIL锁,才能执行解释器代码

2、GIL的优缺点:

优点:  保证Cpython解释器内存管理的线程安全

缺点:同一进程内所有的线程同一时刻只能有一个执行,也就说Cpython解释器的多线程无法实现并行

二、GIL与多线程  

有了GIL的存在,同一时刻同一进程中只有一个线程被执行

听到这里,有的同学立马质问:进程可以利用多核,但是开销大,而python的多线程开销小,但却无法利用多核优势,也就是说python没用了,php才是最牛逼的语言?

要解决这个问题,我们需要在几个点上达成一致:

#1. cpu到底是用来做计算的,还是用来做I/O的?

#2. 多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能

#3. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处 

一个工人相当于cpu,此时计算相当于工人在干活,I/O阻塞相当于为工人干活提供所需原材料的过程,工人干活的过程中如果没有原材料了,则工人干活的过程需要停止,直到等待原材料的到来。

如果你的工厂干的大多数任务都要有准备原材料的过程(I/O密集型),那么你有再多的工人,意义也不大,还不如一个人,在等材料的过程中让工人去干别的活,

反过来讲,如果你的工厂原材料都齐全,那当然是工人越多,效率越高

结论:

  对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用

  当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地

#分析:
我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:
方案一:开启四个进程
方案二:一个进程下,开启四个线程 #单核情况下,分析结果:
  如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
  如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜 #多核情况下,分析结果:
  如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
  如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜 #结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

  

多线程性能测试

 

 1 from multiprocessing import Process
2 from threading import Thread
3 import os,time
4 def work():
5 res=0
6 for i in range(100000000):
7 res*=i
8
9
10 if __name__ == '__main__':
11 l=[]
12 print(os.cpu_count()) #本机为4核
13 start=time.time()
14 for i in range(4):
15 p=Process(target=work) #耗时5s多
16 p=Thread(target=work) #耗时18s多
17 l.append(p)
18 p.start()
19 for p in l:
20 p.join()
21 stop=time.time()
22 print('run time is %s' %(stop-start))

计算密集型:多进程效率高

 1 from multiprocessing import Process
2 from threading import Thread
3 import threading
4 import os,time
5 def work():
6 time.sleep(2)
7 print('===>')
8
9 if __name__ == '__main__':
10 l=[]
11 print(os.cpu_count()) #本机为4核
12 start=time.time()
13 for i in range(400):
14 # p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
15 p=Thread(target=work) #耗时2s多
16 l.append(p)
17 p.start()
18 for p in l:
19 p.join()
20 stop=time.time()
21 print('run time is %s' %(stop-start))

I/O密集型:多线程效率高

三、进程池与线程池    

进程池vs线程池

为什么要用“池”:  池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务

池子内什么时候装进程:并发的任务属于计算密集型

池子内什么时候装线程:并发的任务属于IO密集型

进程池  

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random def task(x):
print('%s 接客' %os.getpid())
time.sleep(random.randint(2,5))
return x**2 if __name__ == '__main__':
p=ProcessPoolExecutor() # 默认开启的进程数是cpu的核数 # alex,武佩奇,杨里,吴晨芋,张三 for i in range(20):
p.submit(task,i)

线程池

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random def task(x):
print('%s 接客' %x)
time.sleep(random.randint(2,5))
return x**2 if __name__ == '__main__':
p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5 # alex,武佩奇,杨里,吴晨芋,张三 for i in range(20):
p.submit(task,i)

四、同步、异步、阻塞、非阻塞

1、阻塞与非阻塞指的是程序的两种运行状态

阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源

非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地,执行其他操作,力求尽可能多的占有CPU

2、同步与异步指的是提交任务的两种方式:

同步调用:提交完任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码

异步调用:提交完任务后,不在原地等待,直接执行下一行代码,结果?

异步调用

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random def task(x):
print('%s 接客' %x)
time.sleep(random.randint(1,3))
return x**2 if __name__ == '__main__':
# 异步调用
p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5 # alex,武佩奇,杨里,吴晨芋,张三 obj_l=[]
for i in range(10):
obj=p.submit(task,i)
obj_l.append(obj) # p.close()
# p.join()
p.shutdown(wait=True) print(obj_l[3].result())
print('主')

  

 同步调用

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random def task(x):
print('%s 接客' %x)
time.sleep(random.randint(1,3))
return x**2 if __name__ == '__main__': # 同步调用
p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5 # alex,武佩奇,杨里,吴晨芋,张三 for i in range(10):
res=p.submit(task,i).result() print('主')

4月27日 python学习总结 GIL、进程池、线程池、同步、异步、阻塞、非阻塞的更多相关文章

  1. Python学习之GIL&进程池/线程池

    8.6 GIL锁** Global interpreter Lock 全局解释器锁 实际就是一把解释器级的互斥锁 In CPython, the global interpreter lock, or ...

  2. 4月2日 python学习总结

    昨天内容回顾: 1.迭代器 可迭代对象: 只要内置有__iter__方法的都是可迭代的对象 既有__iter__,又有__next__方法 调用__iter__方法==>得到内置的迭代器对象 调 ...

  3. 4月8日 python学习总结 模块与包

    一.包 #官网解释 Packages are a way of structuring Python's module namespace by using "dotted module n ...

  4. 4月12日 python学习总结 继承和派生

    一.继承 什么是继承:   继承是一种新建类的方式,在python中支持一个子类继承多个父类   新建类称为子类或派生类   父类可以称之为基类或者超类   子类会遗传父类的属性 2.  为什么继承 ...

  5. 4月11日 python学习总结 对象与类

    1.类的定义 #类的定义 class 类名: 属性='xxx' def __init__(self): self.name='enon' self.age=18 def other_func: pas ...

  6. 4月26日 python学习总结 JoinableQueue、线程、三种锁

    一.进程队列补充-创建进程队列的另一个类JoinableQueue JoinableQueue同样通过multiprocessing使用. 创建队列的另外一个类: JoinableQueue([max ...

  7. 4月18日 python学习总结 异常处理、网络编程

    一. 异常 1.什么是异常 异常是错误发生的信号,程序一旦出错,如果程序中还没有相应的处理机制 那么该错误就会产生一个异常抛出来,程序的运行也随之终止 2.一个异常分为三部分: 1.异常的追踪信息 2 ...

  8. 5月16日 python学习总结 DBUtils模块、orm 和 cookie、session、token

    一.DBUtils模块 介绍 The DBUtils suite is realized as a Python package containing two subsets of modules, ...

  9. 4月20日 python学习总结 套接字工作流程

    一.套接字工作流程 一个生活中的场景.你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了.等交流结束,挂断电话结束此次交谈. 生活中的场景就解释了这 ...

随机推荐

  1. MLlib学习——基本统计

    给定一个数据集,数据分析师一般会先观察一下数据集的基本情况,称之为汇总统计或者概要性统计.一般的概要性统计用于概括一系列观测值,包括位置或集中趋势(比如算术平均值.中位数.众数和四分位均值),展型(比 ...

  2. 测试提高路线图_tester+

    https://mp.weixin.qq.com/s/30ZT0w164Q3iLdPg4R8org

  3. spring boot 配置静态路径

    一  前言 最近有个项目,需要上传一个zip文件(zip文件就是一堆的html压缩组成)的压缩文件,然后后端解压出来,用户可以预览上传好的文件. 查看资料,spring boot对静态文件,可以通过配 ...

  4. Lesson17——NumPy 统计函数

    NumPy 教程目录 1 NumPy 统计函数 NumPy 提供了很多统计函数,用于从数组中查找最小元素,最大元素,百分位标准差和方差等. 函数说明如下 1.1 统计 method descripti ...

  5. 9、Linux基础--编译安装、压缩打包、定时任务

    笔记 1.晨考 1.搭建yum私有仓库的步骤 1.安装工具 yum install createrepo yum-utils nginx -y 2.创建目录 mkdir /opt/test 3.创建包 ...

  6. Solution -「NOI 2021」「洛谷 P7740」机器人游戏

    \(\mathcal{Description}\)   Link.   自己去读题面叭~ \(\mathcal{Solution}\)   首先,参悟[样例解释 #2].一种暴力的思路即为钦定集合 \ ...

  7. CentOS7下Jumpserver V3.0 部署

    环境准备 # 准备一台 2核4G (最低)且可以访问互联网的 64 位 Centos 7 主机 [root@localhost ~]# hostnamectl --static set-hostnam ...

  8. Vue 源码解读(1)—— 前言

    当学习成为了习惯,知识也就变成了常识. 感谢各位的 点赞.收藏和评论. 新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn 文章已收录到 github 仓库 liyongning/blog ...

  9. oracle-11G转10G

    先查询directory的地址 导出的文件必须放在此目录select * from dba_directories;找到directory_name的值 ,也可以新建一个create director ...

  10. harbor服务器脚本

    项目实战,160服务器上安装harbor.mysql等 检查端口 check.sh #!/bin/bash echo -e "\033[31;1;4;5m check mysql... \0 ...