1、GIL

定义:

GIL:全局解释器锁(Global Interpreter Lock)

全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码

为什么需要全局解释器锁

在我们进行代码编写时,实际上我们只是编写了符合python语法的文本文件,如果我们的代码不交给解释器进行解释,那么我们的代码就是一堆字符串,只有在我们将代码交给解释器进行解释时,解释器把我们的代码进行一行一行的解释,解释成一堆二进制,此时再交给cpu进行执行,执行后电脑就会按照我们的代码执行相应的操作。

在python中,我们从来不用关心内存的创建与回收,这个与其他语言不同,其他的一些语言,像C语言,在创建变量时,必须手动的创建内存空间进行数据的存储,在这个数据使用完毕后,再手动的将内存进行回收,为什么我们不需要关心内存的创建与回收呢?

这是因为,我们现在使用的解释器时Cpython解释器,Cpython是由C语言编写的,在C语言中,有很多已经封装好的关于进程线程以及对于内存管理的模块,在解释器解释执行我们的代码时,已经默默的将开辟内存的操作执行了,所以我们不需要自己进行操作

在python中,还有一套垃圾回收机制,垃圾回收机制的工作原理是,在每个开辟的内存空间上添加引用计数,如果引用计数不为0,那么这块空间就会被编辑为不可用状态,当一个内存空间如果被引用多次时,其内存空间上的引用计数就会相应的增加,当所有的引用全部断开后,其引用计数就会就会变为0,同时垃圾回收机制的原理就是隔一段时间扫描一次内存空间,将内存空间中引用计数为0的内存区域重新标记为可用状态,那么下次再有数据要创建时就有可能使用这片空间

垃圾回收机制不是凭空产生的,他也是一段代码,也会产生一个线程,隔一段时间就会被执行一次,此时也需要被解释器进行解释,问题就出现在了这里,由于Cpython是线程不安全的,当我们创建内存空间时,如果内存空间创建到了一半,此时我们的代码执行时间到了,或者使用解释器时间过长就会被解释器挂起,开始执行另一端代码,此时如果恰好是垃圾回收机制进行解释,扫描内存空间,由于我们的内存空间还没有创建好,引用计数还没有进行加一,那么此块区域就有可能被回收,此时问题就产生了,当下次解释器再执行到我们的代码时开始执行引用计数加一的操作就会出错,因为此块区域已经被当做是垃圾回收了,那么我们应该怎样处理呢?

全局解释器锁应运而生,我们将解释器进行加锁,当年我们的代码拿到了解释器的使用权后就对解释器加锁,此时在同一个进程中,同一时间就只有一个线程在使用解释器执行,此时我们手持着这把锁,垃圾回收机制或者是其它的进程就不能使用解释器,从而达到线程安全的目的

全局解释器锁产生的问题

在添加了全局解释器锁以后,实际上多线程已经不能够实现并行的效果了,因为同一时间只有一个线程在执行,其它线程只能在锁释放后在使用锁,这个问题在单核处理器时代什么问题都没有,但是到了多核处理器时代,问题就出现了,由于多核时代可以真正的实现并行,那么多个线程就有可能同时执行,此时由于全局解释器锁的问题,python就不能实现真正的并行,只能实现并发

2、多进程以及多线程的选择

又有多进程又有多线程那么应该怎么选择呢?

当我们执行IO密集型的操作时,此时应该使用多线程

因为在进行IO密集型的操作时,由于IO操作相对于CPU的执行速度很慢很慢,此时如果使用多线程进行操作,也就是并发,是不会影响CPU的执行的,此时的短板在IO操作,如果换成多进程,也不会影响CPU的执行,在cpu切换过程中就能将这些数据处理完成,且不会等待,但是由于开启多进程所消耗的资源比较大,所以开启多线程会比较合适

当我们执行计算密集型的操作时,此时应该使用多进程

由于在执行数据密集型操作时,cpu一直在执行,此时只有时间片用完之后才会切换,此时数据的计算就需要等待CPU再次切换过来,此时如果开启多进程,由于进程之间使用不同的解释器,所以此时是在进行并行,执行的效率就会提高,所以在进行数据密集型作业时,推荐使用多进程

3、同步与异步

同步:同步的意思是在执行程序时,下一步的操作需要等待上一步执行完毕后才会执行

异步:程序在开启子进程或者子线程后不用等待程序的运行,可以直接执行后续的代码,不需要等待当子进程或字线程执行完毕

4、进程池、线程池

池:就是一个大池子,用术语来描述就是一个容器

进程池就是储存进程的容器

进程池与线程池基本相同

其使用为:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time

# 开启多进程
def test():
print("线程开启")
time.sleep(5)
print("线程结束")
# 开启一个线程池,其中线程池种可以容纳最大线程数默认为 cpu数量 * 5
t_pool = ThreadPoolExecutor()

# 将想要线程执行的代码交给线程池进行执行
t_pool.submit(test)

print("over")

# 开启多进程
def test():
print("线程开启")
time.sleep(5)
print("线程结束")

# 开启一个线程池,其中线程池种可以容纳最大线程数默认为 cpu数量 * 5
if __name__ == '__main__':
t_pool = ProcessPoolExecutor()
# 将想要线程执行的代码交给线程池进行执行
t_pool.submit(test)

# shutdown方法
pool.shutdown() # 在等到所有的线程都结束时,将线程池回收,如果还有线程在执行,则会进入等待状态

print("over")

在创建进程池以及创建线程池时不能直接将进程或者线程提前创建出来,只是为创建的进程以及线程增加一个最大值

使用进程线程池与自己开启进程线程的区别:

  • 进程池封装了开启以销毁,我们不需要在开启线程

  • 线程池中的线程不会被杀死,只有在系统重启时才会消失

  • 控制线程开启的数量,保证系统的稳定性

4、回调函数

我们可以使用同步或者异步执行我们的程序,那么如果我们的父进程或者主线程需要子进程或者子线程的执行结果又该怎么办呢?

有两种方法:

一种是使用同步的方式,在子线程执行完毕后再执行后续的代码,但是此时失去了开启子进程或者子线程的意义了

另一种方法是使用异步的方式,开启子进程或者子线程后不再管子线程,当其执行结束后直接使用其执行结果,但是我们有应该怎么知道自己成什么时间结束呢?子线程什么时间结束只有子进程自己知道,那么有一种方法可以让子进程执行结束后将结果返回给父进程呢?

还真的有这种方法,这就是回调函数

回调函数在进程池以及线程池中可以使用,使用方法为:

import time
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor,_base
from concurrent.futures._base import Future

def task():
time.sleep(5)
return "子线程结束"


def future(args:Future):
print(args.result())


pool = ThreadPoolExecutor()
res = pool.submit(task)
res.add_done_callback(future)


print("over")

线程池中的线程使用回调函数,回调函数的执行还是在本线程执行,原因是 任务是由父进程发起的,所以结果也应该交给父进程

进程池中的回调函数,回调函数在执行时会将函数放到父进程中执行(会自动解决进程中通讯问题),原因是 线程之间数据本来是共享的

如果你的任务结果需要交给父进程来处理,那建议回调函数,回调函数会自动将数据返回给父进程,不需要自己处理IPC

day37 GIL、同步、异步、进程池、线程池、回调函数的更多相关文章

  1. GIL全局解释器锁,线程池与进程池 同步异步,阻塞与非阻塞,异步回调

    GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents ...

  2. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

  3. 13 并发编程-(线程)-异步调用与回调机制&进程池线程池小练习

    #提交任务的两种方式 #1.同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果,再执行下一行代码,导致程序是串行执行 一.提交任务的两种方式 1.同步调用:提交任务后,就在原地等待任务完毕,拿 ...

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

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

  5. Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池

    Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...

  6. node源码详解(七) —— 文件异步io、线程池【互斥锁、条件变量、管道、事件对象】

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource7 本博客同步在https://cnodejs.o ...

  7. concurrent.futures模块(进程池/线程池)

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  8. python并发编程-进程池线程池-协程-I/O模型-04

    目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...

  9. Python-GIL 进程池 线程池

    5.GIL vs 互斥锁(*****) 1.什么是GIL(Global Interpreter Lock) GIL是全局解释器锁,是加到解释器身上的,保护的就是解释器级别的数据 (比如垃圾回收的数据) ...

  10. Python标准模块--concurrent.futures 进程池线程池终极用法

    concurrent.futures 这个模块是异步调用的机制concurrent.futures 提交任务都是用submitfor + submit 多个任务的提交shutdown 是等效于Pool ...

随机推荐

  1. 【JAVA-算法】 截取2个字符中间的字符串

    Java Code /** 截取2个字符中间的字符串 */ private void GetMiddleString() { String str = "BB022220011BB007EB ...

  2. MFC 模态对话框、非模态对话框

    modal dialogs与modeless dialogs,modal dialogs会让原窗体不被选中,modeless dialogs原窗体依然可以选中. 1.模态对话框的显示 DlgModal ...

  3. nginx大概工作机制

    1.master和worker nginx启动后,会有2种进程:worker和master;worker可能有多个:

  4. find(expr|obj|ele)搜索所有与指定表达式匹配的元素。

    find(expr|obj|ele) 概述 搜索所有与指定表达式匹配的元素.这个函数是找出正在处理的元素的后代元素的好方法. 所有搜索都依靠jQuery表达式来完成.这个表达式可以使用CSS1-3的选 ...

  5. 【csp模拟赛4】旅行计划 (travelling.cpp)--欧拉回路

    [题目描述] 小 Z 打算趁着暑假,开启他的旅行计划.但与其他同学不同的是,小 Z 旅 行时并不关心到达了哪个网红景点打了哪些卡.小 Z 更关注沿路的风光,而且 小 Z 觉得,尽管多次到达同一个地方, ...

  6. 7.20套娃(tao)

    套娃(tao) input7 39 53 710 65 102 610 104 110 53 53 9output012 sol: 把查询想象成(x1,y1)向(x2,y2)有边当且仅当(x1< ...

  7. shell脚本中根据端口号kill对应的应用进程

    一.使用情景 在Jenkins的自动部署中,每次重新部署我们都需要先关闭原先的应用进程,然后重新部署启动.在使用tomcat时,我们可以通过startup.sh和shutdown.sh进行对应操作.但 ...

  8. Leetcode题目39.组合总和(回溯+剪枝-中等)

    题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无 ...

  9. apidoc 接口文档系统

    代码未动,文档先行.apidoc可以方便地维护接口文档.模拟响应数据.前后端分离.导出PDF文档. 特性说明 可视化编辑:支持表单界面编辑接口,不必手动编辑swagger.json 接口模拟响应:支持 ...

  10. nginx 错误集锦

    1)下载地址 http://nginx.org/en/download.html 找windows的下载. 2)然后解压到自己的一个目录. 3)配置环境变量,将解压到的路径加进去. 4)修改配置文件 ...