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. 洛谷-P3796-AC自动机加强版

    链接: https://www.luogu.org/problem/P3796 题意: 有NN个由小写字母组成的模式串以及一个文本串TT.每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本 ...

  2. The Reset Method of Te Philips VTR 5210

    Pull down and hold the ON/OFF buttun, Then press the play button

  3. Zw函数与Nt函数的分别与联系

    Ring3中的NATIVE API,和Ring0的系统调用,都有同名的Zw和Nt系列函数,一度让初学者感到迷糊.N久前的我,也是相当的迷糊.现在就以ZwOpenProcess和NtOpenProces ...

  4. 在 CentOS 7 上安装 RabbitMQ

    RabbitMQ 服务器在安装之前需要安装 erlang. 最新版本的 RabbitMQ 3.8.0 需要 Erlang 21.3 以上的版本支持. 在这里,我们需要在你的 CentOS 中安装 Er ...

  5. 求后序遍历x

    题目描述 Description 输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列. 输入描述 Input Description 共两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串, ...

  6. Spring Boot中@OneToMany与@ManyToOne几个需要注意的问题

    @OneToMany如果不加@JoinColumn,系统会自动在主从表中增加一个中间表. 主表: @Entity(name = "Post") public class Post  ...

  7. XCTest-iOS单元测试框架

    Xctest    是iOS的单元测试框架,有objective-c和swift两种语言可以选择 Xcuitest  是iOS的UI测试框架   XCTest 官方文档地址:https://devel ...

  8. Cocos Creator中按钮组件数组的使用

    Cocos Creator游戏开发中经常使用到按钮,特别是大量按钮的情况,此时使用数组来管理这些按钮就显得更具通用性.我大致走了一下官方的示例,好像没有发现有这个小内容(或者有,但我却是没有找到),于 ...

  9. js off动画事件

    每个假期都过得如此快10月一是2017年最后一个假期.不由感叹时间过得真快.我已上个月离职,一直在家休整,今天得空吧前几天学习的知识真理一下. 今天主要整理关于,offset系列的,动画是咱们全都工作 ...

  10. deep sort

    目录   1. 准备代码与数据 deep_sort开源代码 克隆到本地服务器 git clone https://github.com/nwojke/deep_sort.git 下载MOT16数据集( ...