Python 进程线程协程 GIL 闭包 与高阶函数(五)
Python 进程线程协程 GIL 闭包 与高阶函数(五)
1 GIL线程全局锁
线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。
在分析线程全局锁之前我们先聊下python.
(1) python语言的症结
python是解释型语言 , 不像c++这样是编译型语言 : 程序输入到编译器,编译器再根据语言的语法进行解析 . 编译型语言之所以可以进行深层次的底层优化是因为可以直接看到代码的整体部分,这使得它可以对不同的语言指令之间的交互进行推理,从而给出更有效的优化手段。
Python是解释型语言,程序被输入到解释器运行,解释器只会按照python的规则以及在执行过程中怎样去动态的应用这些规则,由于解释器没法很好的对程序进行推导. 而Python大部分的优化也是解释器自身的优化, 换句话说,解释器优化后,Python不用修改源代码就能享受优化的好处. 因此关键问题来了,如果假定其他条件不变, python程序的执行速度跟解释器速度相关 . 不管你怎样优化自己的程序,你的程序的执行速度还是依赖于解释器执行你的程序的效率。这就很明显的解释了为什么我们需要对优化Python解释器做这么多的工作了。
(2) Python的多线程
要想利用多核系统,Python必须支持多线程运行. 目前来说,多线程执行还是利用多核系统最常用的方式 .,但是多个线程竞争一个共享资源数据将会是意见很糟糕的事, 因此解释器要留意的是避免在不同的线程操作内部共享的数据。同时它还要保证在管理用户线程时保证总是有最大化的计算资源。那么数据的安全机制怎么操作呢? 答案就是解释器全局锁 , 这是一个加在解释器上的全局锁。这种方式当然很安全,但是它隐含意思:对于任何Python程序,不管有多少的处理器,任何时候都总是只有一个线程在执行。
这就是为什么总会碰到 ''全新的多线程Python程序运行得比其只有一个线程的时候还要慢? ''
(3) 如何解决GIL
很多有经验的开发人员都会回答:"不要使用多线程,使用多进程!!",但是这并没有解决多线程的核心问题, 国外有做过这方面的尝试,通过移除GIL,且用细粒度的锁来代替,但是带来的代价是单线程执行程序运行速度下降很大.在新的GIL中, 用一个固定的超时时间来指示当前的线程以放弃这个锁。在当前线程保持这个锁,且当第二个线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁(这就是说,当前线程每5ms就要检查其是否需要释放这个锁)。当任务是可行的时候,这会使得线程间的切换更加可预测。 但是这也不是一个完美的方案, 因此GIL线程全局锁仍然是Python最大的挑战,希望有大牛能完美解决!!!!
2 线程 进程与协程
多线程
线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除 .
多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果。
多线程相当于一个并发(concunrrency)系统。并发系统一般同时执行多个任务。如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题.
在并发情况下,指令执行的先后顺序由内核决定。同一个线程内部,指令按照先后顺序执行,但不同线程之间的指令很难说清除哪一个会先执行。因此要考虑多线程同步的问题。同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源。
协程
与线程的抢占式调度不同,它是协作式调度。协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来。
1 协程在python中可以由生成器(generator )来实现 即可以通过yield控制程序的运行
2 Stackless Python
3 greenlet模块
4 eventlet模块
多进程
multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。
1 进程池 (Process Pool)可以创建多个进程。
2 apply_async(func,args) 从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你可以对该对象调用get()方法以获得结果。
3 close() 进程池不再创建新的进程
4 join() wait进程池中的全部进程。必须对Pool先调用close()方法才能join。
3 闭包
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
当一个内嵌函数引用其外部作作用域的变量,我们就会得到一个闭包. 重点是函数运行后并不会被撤销,只是迁移到内函数上 ,总结一下,创建一个闭包必须满足以下几点:
- 必须有一个内嵌函数
- 内嵌函数必须引用外部函数中的变量
- 外部函数的返回值必须是内嵌函数
#闭包函数的实例
# outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
b = 10
# inner是内函数
def inner():
#在内函数中 用到了外函数的临时变量
print(a+b)
# 外函数的返回值是内函数的引用
return inner
if __name__ == '__main__':
# 在这里我们调用外函数传入参数5
#此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
demo = outer(5)
# demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
demo() # 15
demo2 = outer(7)
demo2()#17
外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数,因此外函数的结束并没有清空a,b的数值,而是绑定给了内函数。
4 高阶函数,函数式编程
(1)lambda函数
lambda函数也成为匿名函数是函数式编程的一种,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,同类的还有filter ,reduce等等
#将list每个元素进行平方
#map的语法是 : map(f,a) 也就是将函数 f 依次套用在 a 的每一个元素上面
map( lambda x: x*x, [y for y in range(10)] )
#类似于下面的写法
def sq(x):
return x * x
map(sq, [y for y in range(10)])
#多定义了一个函数,尤其在只是用一次的情况下
所以你会发现自己如果能将「遍历列表,给遇到的每个元素都做某种运算」的过程从一个循环里抽象出来成为一个高阶函数 map,然后用 lambda 表达式将这种运算作为参数传给 map 的话,思维水平就要高出一般的原写法。
(2)reduce函数
reduce()函数也是Python内置的一个高阶函数。
reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
def f(x, y):
return x + y
reduce(f, [1, 3, 5, 7, 9])
#先计算头两个元素:f(1, 3),结果为4;
#再把结果和第3个元素计算:f(4, 5),结果为9;
#再把结果和第4个元素计算:f(9, 7),结果为16;
#再把结果和第5个元素计算:f(16, 9),结果为25;
#由于没有更多的元素了,计算结束,返回结果25
(3) filter函数
filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
#list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数
def is_odd(x):
return x % 2 == 1
filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
#输出
[1, 7, 9, 17]
当然还可以实现很多功能,取决与函数定义的功能(删除 None 或者空字符串 等),filter仅仅是辅助函数起到过滤作用。
(4)函数式编程
def func(x):
def funcx(y):
return x+y
return funcx
func2 = func(2)
func5 = func(5)
print(func2(5)) # 输出 7
print(func5(5)) # 输出 10
inc()函数返回了另一个函数incx(),于是我们可以用inc()函数来构造各种版本的inc函数,比如:inc2()和inc5()。这个技术其实就是上面所说的Currying技术。从这个技术上,你可能体会到函数式编程的理念:把函数当成变量来用,关注于描述问题而不是怎么实现,这样可以让代码更易读。
Python 进程线程协程 GIL 闭包 与高阶函数(五)的更多相关文章
- 多道技术 进程 线程 协程 GIL锁 同步异步 高并发的解决方案 生产者消费者模型
本文基本内容 多道技术 进程 线程 协程 并发 多线程 多进程 线程池 进程池 GIL锁 互斥锁 网络IO 同步 异步等 实现高并发的几种方式 协程:单线程实现并发 一 多道技术 产生背景 所有程序串 ...
- python 进程 线程 协程
并发与并行:并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔内发生.在单核CPU下的多线程其实都只是并发,不是并行. 进程是系统资源分配的最小单位,进程的出现是为了更好的 ...
- python -- 进程线程协程专题
进程专栏 multiprocessing 高级模块 要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识. Unix/Linux操作系统提供了一个fork() ...
- python进程/线程/协程
一 背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所 ...
- python 进程/线程/协程 测试
# Author: yeshengbao # -- coding: utf-8 -- # @Time : 2018/5/24 21:38 # 进程:如一个人拥有分身(分数数最好为cpu核心数)几乎同时 ...
- python自动化开发学习 进程, 线程, 协程
python自动化开发学习 进程, 线程, 协程 前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...
- Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程
1 引言 并发.并行.串行.同步.异步.阻塞.非阻塞.进程.线程.协程是并发编程中的常见概念,相似却也有却不尽相同,令人头痛,这一篇博文中我们来区分一下这些概念. 2 并发与并行 在解释并发与并行之前 ...
- 进程&线程&协程
进程 一.基本概念 进程是系统资源分配的最小单位, 程序隔离的边界系统由一个个进程(程序)组成.一般情况下,包括文本区域(text region).数据区域(data region)和堆栈(stac ...
- [Node.js] 闭包和高阶函数
原文地址:http://www.moye.me/2014/12/29/closure_higher-order-function/ 引子 最近发现一个问题:一部分写JS的人,其实对于函数式编程的概念并 ...
随机推荐
- LeetCode记录之7——Reverse Integer
Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 Note:The ...
- bugzilla部署问题
2018-09-25 1.部署环境 kvm虚拟机内 centos 7 系统 httpd+mariadb+bugzilla 关闭系统selinux.防火墙 setenforce 临时关闭se ...
- pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple 快速下载
- (转)shell脚本之文件测试操作符及整数比较符
shell脚本之文件测试操作符及整数比较符 原文:http://www.cnblogs.com/Steward-Xu/p/6722592.html 一.文件测试操作符: 在书写测试表达式是,可以使用一 ...
- (转)python编写登录接口
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://506554897.blog.51cto.com/2823970/1907262 ...
- layer框架使用的问题汇总
一.如何设置弹出框弹出后不影响页面的其他操作 解决:在属性中添加设置zIndex即可
- 新建maven工程index.jsp页面报错
引入servlet依赖jar <dependency><groupId>javax.servlet</groupId><artifactId>servl ...
- 自己实现C++的string类
使用C++的朋友对string类都不会陌生,string类使用起来很是方便,比C的字符数组好用多了,但是我们能不能自己实现一个属于自己的string类呢? 实现一个具有基本功能的string类并不难, ...
- Linux.net && mono
资料: http://www.cnblogs.com/xiaodiejinghong/archive/2013/04/01/2994216.html http://www.cnblogs.com/sh ...
- 世界、国家、省、城市SQL
共享一份 世界.国家.省.城市最全的SQL(mysql可直接使用),笔者是花了下载币下载的 下载SQL # pid=0 获取所有国家 # pid=99999999 获取中国的省.自治区.直辖 ...