一、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. Python中set集合常用操作

    功能 Python符号 Python方法 备注 交集 & intersection, intersection_update &:取两者交集>>> set3 = se ...

  2. python基础语法_10错误与异常

    Python有两种错误很容易辨认:语法错误和异常. 语法错误 Python 的语法错误或者称之为解析错,是初学者经常碰到的,如下实例 异常 即便Python程序的语法是正确的,在运行它的时候,也有可能 ...

  3. 私有化轻量级持续集成部署方案--02-Nginx网关服务

    提示:本系列笔记全部存在于 Github, 可以直接在 Github 查看全部笔记 这一篇中使用 Nginx 部署网关中心,用来代理服务器中服务.网关中心有优点也有缺点,也可以不采用网关系统. 部署 ...

  4. Solution -「NOI 2020」「洛谷 P6776」超现实树

    \(\mathcal{Description}\)   Link.   对于非空二叉树 \(T\),定义 \(\operatorname{grow}(T)\) 为所有能通过若干次"替换 \( ...

  5. 【软件实施面试】MySQL和Oracle联合查询以及聚合函数面试总结

    软件实施面试系列文章第二弹,MySQL和Oracle联合查询以及聚合函数的面试总结.放眼望去全是MySQL,就不能来点Oracle吗?之前面过不少公司,也做过不少笔试题,现在已经很少做笔试题了.你肚子 ...

  6. rust连接oracle数据库遇到DPI-1047: Cannot locate a 64-bit Oracle Client library的解决方案

    这两天要实现一个用rust连接远程的oracle数据库的需求,所以就需要用rust连接oracle. 在github上面找到一个库,地址:https://github.com/kubo/rust-or ...

  7. mysql悬案 之 为什么用docker启动的mysql配置文件不生效

    文章目录 故事前景 查看docker启动时挂载了哪些目录 使用相同镜像启动一个mysql 新建一个目录用来存放容器内的mysql配置文件 复制容器内的mysql配置文件到本地 查看mysql配置文件目 ...

  8. CentOS7 下 ldap 部署

    环境准备 # 关闭防火墙以及selinux,生产环境中,以实际需求为准 [root@localhost ~]# hostnamectl --static set-hostname ldap-serve ...

  9. 阿里云K8S节点NotReady状态

    开发部署pod的时候在wayne平台上部署不上去,删除也删除不了 先删除 kubectl delete pod pod-name --grace-period=0 --force 删除之后然后部署新的 ...

  10. 攻防世界之Web_php_rce

    题目: ========================================================================== 解题思路: 1.这题主要考查ThinkPH ...