python多线程

并发编程(三)

六眼飞鱼酱① 提交于 2020-01-22 09:13:43
并发编程(三) >>> 思维导图 >>> 中二青年 GIL全局解释器锁 Cpython解释器:python解释器有很多种,最常见的就是Cpython解释器 GIL本质也是一把互斥锁 将并发变成串行牺牲效率保证数据的安全 用来阻止同一个进程下的多个线程的同时执行 (同一个进程内多个线程无法实现并行但是可以实现并发) GIL的存在是因为CPython解释器的内存管理不是线程安全的 因为进程内的垃圾回收机制也是一个线程,所以有可能造成其他线程例如赋值时,刚创建值,还没指向变量名就被回收,再赋值直接报错 python的多线程没法利用多核优势 是不是就是没有用了? 研究python的多线程是否有用需要分情况讨论 四个任务 计算密集型的 10s 单核情况下 开线程更省资源 多核情况下 开进程 10s 开线程 40s 四个任务 IO密集型的 单核情况下 开线程更节省资源 多核情况下 开线程更节省资源 python的多线程到底有没有用 需要看情况而定 并且肯定是有用的 多进程+多线程配合使用 多线程不能使用多核是所有解释型语言的通病 GIL与普通互斥锁 from threading import Thread import time n = 100 def task(): global n tmp = n # time.sleep(1) n = tmp -1 t_list = [] for i

Python多线程中阻塞(join)与锁(Lock)的使用方式

时间秒杀一切 提交于 2020-01-22 00:33:46
关于阻塞主线程 join的错误用法 Thread.join() 作用为阻塞主线程,即在子线程未返回的时候,主线程等待其返回然后再继续执行. join不能与start在循环里连用 以下为错误代码,代码创建了5个线程,然后用一个循环激活线程,激活之后令其阻塞主线程. threads = [ Thread ( ) for i in range ( 5 ) ] for thread in threads : thread . start ( ) thread . join ( ) 执行过程: 第一次循环中,主线程通过start函数激活线程1,线程1进行计算. 由于start函数不阻塞主线程,在线程1进行运算的同时,主线程向下执行join函数. 执行join之后,主线程被线程1阻塞,在线程1返回结果之前,主线程无法执行下一轮循环. 线程1计算完成之后,解除对主线程的阻塞. 主线程进入下一轮循环,激活线程2并被其阻塞… 如此往复,可以看出,本来应该并发的五个线程,在这里变成了顺序队列,效率和单线程无异. join的正确用法 使用两个循环分别处理start和join函数.即可实现并发. threads = [ Thread ( ) for i in range ( 5 ) ] for thread in threads : thread . start ( ) for thread in

多线程

允我心安 提交于 2020-01-21 07:34:47
进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位 多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间. 创建进程的开销远大于线程 不同的进程之间是竞争关系,同一个进程的线程之间是合作关系 线程共享创建他的进程的地址空间,进程有自己的地址空间 线程可以直接访问其进程的数据段,进程有它们自己的父进程的数据段副本 线程可以直接与进程的其他线程通信,进程必须使用进程间通信来与兄弟进程通信 容易创建新线程,新进程需要父进程的复制 线程可以对同一进程的线程进行相当大的控制,流程只能对子流程进行控制 对主线程的更改(取消,优先级更改等)可能会影响进程中其他线程的行为.对父进程的更改不会影响子进程 多线程指的是,在一个进程中开启多个线程, 1.多线程共享一个进程的地址空间 2.线程比进程更加轻量级,线程比进程更容易创建和撤销 3.若多个线程都是cpu密集型的,那么并不能获得性能上的增强,如果需要大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度 4.在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小得多(不适用于python) 开启线程的两种方式: 1.通过继承Thread类,覆盖run方法,生成线程对象 2.调用Thread方法

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

孤者浪人 提交于 2020-01-21 05:49:27
一、进程队列补充-创建进程队列的另一个类JoinableQueue JoinableQueue同样通过multiprocessing使用。 创建队列的另外一个类: JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。 参数介绍: maxsize是队列中允许最大项数,省略则无大小限制。 方法介绍: JoinableQueue的实例p除了与Queue对象相同的方法之外还具有: q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常 q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止 1 import time 2 import random 3 from multiprocessing import Process,JoinableQueue 4 5 def consumer(name,q): 6 while True: 7 res=q.get() 8 if res is None:break 9 time.sleep(random.randint(1,3))

Python-协程

风格不统一 提交于 2020-01-20 04:14:24
一、引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质: 切换+保存状态 。 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制): 一种情况是该任务发生了阻塞; 另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它。 协程本质上就是一个线程,以前线程任务的切换是由操作系统控制的,遇到I/O自动切换,现在我们用协程的目的就是较少操作系统切换的开销(开关线程,创建寄存器、堆栈等,在他们之间进行切换等),在我们自己的程序里面来控制任务的切换。 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 需要 注意 的是: 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled 可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send 可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 通过yield实现

Python多线程和GIL锁

一曲冷凌霜 提交于 2020-01-20 03:10:07
Python 有GIL锁,所以它的多线程实际上是单线程 GIL 全称全局解释器锁(Global Interpreter Lock), 它锁的解释器,而不是Python代码,它防止多线程同时执行Python的字节码, 防止多线程同时访问Python的对象 Python的解释器通过切换线程的方式来模拟多线程并发的情况 那岂不是说Python多线程不会提高效率了??? 非也!!! 对于IO密集型工作,多线程可以大幅度提高效率,而对于CPU密集型工作,多线程是没用的. IO密集型 涉及到网络,磁盘IO,硬盘读写等都是IO密集型工作,这类任务对CPU的消耗较少,大部分时间不是花在代码上,而是其他操作上 CPU密集型 特点是进行大量的计算,消耗CPU资源, 比如我们常见的排序算法,对视频的解码之类的,大部分时间花在代码上 最后: CPU密集型程序适合用C等编译型语言开发的多线程, 而IO密集型程序适合Python等脚本语言开发的多线程 在使用多线程的时候,多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁,类似于协程. 在处理像科学计算 这类需要持续使用cpu的任务的时候 单线程会比多线程快 在 处理像IO操作等可能引起阻塞的这类任务的时候 多线程会比单线程 来源: CSDN 作者: print('hello world') 链接: https://blog.csdn.net

多线程和多进程

旧时模样 提交于 2020-01-19 16:13:03
一、线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。进程是很多资源的集合。 有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。 由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。线程是最小的执行单元,而进程由至少一个线程组成。 我们在做事情的时候,一个人做是比较慢的,如果多个人一起来做的话,就比较快了,程序也是一样的,我们想运行的速度快一点的话,就得使用多进程,或者多线程,在python里面,多线程被很多人诟病,为什么呢,因为Python的解释器使用了GIL的一个叫全局解释器锁,它不能利用多核CPU,只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的

Flask框架之ThreadLocal变量

青春壹個敷衍的年華 提交于 2020-01-19 02:27:14
Local对象隔离线程间的对象_即ThreadLocal变量 Local对象 在Flask中,类似于 request 对象,其实是绑定到了一个 werkzeug.local.Local 对象上。 这样,即使是同一个对象,那么在多个线程中都是隔离的。 类似的对象还有 session 以及 g 对象。 flask=werkzeug + sqlalchemy + jinja2 ThreadLocal变量 Python 提供了 ThreadLocal 变量,它本身是一个全局变量,但是每个线程却可以利用它来保存属于自己的私有数据,这些私有数据对其他线程也是不可见的。 总结: 只要满足绑定到 local 或 Local 对象上的属性,在每个线程中都是隔离的,那么他就叫做 ThreadLocal 对象,也叫 ThreadLocal 变量。 python中的线程 from threading import Thread , local local = local ( ) local . request = '具体用户的请求对象' class MyThread ( Thread ) : def run ( self ) : local . request = 'wukong' print ( '子线程:' , local . request ) mythread = MyThread ( )

python 数据结构 队列(queue)

房东的猫 提交于 2020-01-18 13:41:30
如需转发,请注明出处: 小婷儿的 python https://www.cnblogs.com/xxtalhr/p/10293817.html 欢迎关注小婷儿的 博客: 有问题请在博客下留言或加 作者微信 : tinghai87605025 或 QQ : 87605025 python QQ 交流群: py_data 483766429 博客园: http://www.cnblogs.com/xxtalhr/ csdn : https://blog.csdn.net/u010986753 一、概念 队列( queue )是一种先进先出的( First In First Out )的线性表,简称 FIFO 。队列允许在一端进行插入操作,而在另一端进行删除操作。允许插入的一端为队尾,允许删除的一端为队头。队列不允许在中间部位进行操作 二、作用    解耦:使程序直接实现松耦合,修改一个函数,不会有串联关系。    提高处理效率:FIFO = 现进先出,LIFO = 后入先出。 注 : 队列可以并发的派多个线程,对排列的线程处理,并切每个需要处理线程只需要将请求的数据放入队列容器的内存中,线程不需要等待,当排列完毕处理完数据后,线程在准时来取数据即可。请求数据的线程只与这个队列容器存在关系,处理数据的线程 down掉不会影响到请求数据的线程,队列会派给其他线程处理这分数据,它实现了解耦

线程中的队列(queue)

落爺英雄遲暮 提交于 2020-01-18 13:41:15
队列的类型和常用方法 队列是一种数据结构,它类似于列表。但列表是线程不安全的,而队列是线程安全的。 python的queue(python3,python2为Queue)提供了3种队列: Queue:先进先出型(First In First Out)。 LifoQueue:后进先出型(Last In First Out)。 PriorityQueue:优先级型,为队列中的元素自定义优先级,按照优先级获取元素。 每种队列的构造方法都有一个maxsize的属性,默认为0,该属性用来指定队列存放的最大元素个数。如果为0或小于0,则队列是无限长的。 队列中的方法: q.put(10):将某个元素放到队列中。该方法中的参数item(即要存放的元素)是必须指定的; 参数block=True,该参数是否采取阻塞的方式向队列中放置元素。如果block=True,则put方法会在队列已经满了的情况(没有空余位置)下阻塞,直到队列中空出位置后再将元素放置到队列中;如果block=False,不论队列是否有空余位置都会尝试将元素放到队列中,当队列已满时会抛出“满队列异常(Full exception)”。q.put_nowait()方法相当于q.put(block=False)。 参数timeout=None,当该参数被设置为x(大于或等于0)时,put方法最多会阻塞x秒,之后尝试向队列中存放元素