python多线程

协程

扶醉桌前 提交于 2020-01-04 05:11:24
1、协程的理解 协程,又称微线程,纤程。英文名Coroutine,是一种用户态的轻量级线程。 注意:   1. python的线程属于内核级别的,即由操作系统控制调度(如单线程一旦遇到io就被迫交出cpu执行权限,切换其他线程运行)   2. 单线程内开启协程,一旦遇到io,从应用程序级别(而非操作系统)控制切换 协程优点:   1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级   2. 单线程内就可以实现并发的效果,最大限度地利用cpu 协程缺点:   1.协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程   2.协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程 协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方(线程调度时候寄存器上下文及栈等保存在内存中),在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。 所以子程序调用是通过栈实现的

Day 35 协程

霸气de小男生 提交于 2020-01-04 05:11:11
目录 day 35 协程 线程队列 运算符重载 单线程实现并发处理 如何实现 Greenlet模块实现并发 协程 Gevent模块 day 35 协程 线程队列 就是一个普通的容器 Queue:就是类似JoinableQueue LifoQueue:先进后出,类似堆栈,与Queue的区别仅在于顺序不同 PriorityQueue:具备优先级的队列,在取出数据时会比较大小,越小优先级越高,如果存入的数据是多值数据类型时,会比较第一个元素,再比较第二个元素 运算符重载 自定义对象无法使用比较运算符 这是因为自定义兑现更没有实现用于比较的方法,即__lt__和__gt__ lt方法用于比较当前对象是否小于另一个对象 gt方法用于比较当前对象现是否大于另一个对象 当使用比较运算符时,会自动触发执行,并传入当前对象和比较对象,返回值是布尔值 单线程实现并发处理 GIL导致cpython中多线程无法并行执行,只能并发执行,效率低 并发是我们要是现在的最终目的,(最好是并行) 由于GIL锁多个线程只能切换执行,创建销毁线程需要消耗资源,切换线程也需要消耗资源并且最主要的问题是多线程容易出现假死问题,例如tcp服务器限制了最大线程数量为1000 如果这1000个客户端有一部分没有进行任何操作,而新的任务将无法被处理,即使cpu是空闲的,这样就造成了资源的浪费 办法:让单个线程负责处理所有任务

python之协程

心不动则不痛 提交于 2020-01-04 05:11:02
一、协程理论 1.1 协程产生的背景 之前我们学习了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU执行的最小单位。 随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。 本节我们就基于单线程来实现并发,首先我们要回顾一下并发的本质: 切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制) (1)该任务发生了阻塞 (2)该任务计算时间过长或有个更高级的程序替代它 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 注意点1 第二种情况本质上并不能提高效率,只是为了cpu能雨露均沾,实现看起来所有任务被“同时”执行,如果多个任务是纯计算的,单纯的切换反而会降低效率。 1.2 yield实现并发 我们通过yield验证,yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 yield实现并发的缺点: (1

网络编程和并发之协程

一笑奈何 提交于 2020-01-04 05:10:34
一、引入  之前我们学习了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位。 按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。   随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。   为此我们需要先回顾下并发的本质:切换+保存状态   cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长       ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态    一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。   为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的

DAY10-python并发编程之携程

倾然丶 夕夏残阳落幕 提交于 2020-01-04 05:10:10
一、引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 #串行执行 import time def consumer(res): '''任务1:接收数据,处理数据''' pass def producer(): '''任务2:生产数据''' res=[] for i in range(10000000): res.append(i)

并发编程之协程

天大地大妈咪最大 提交于 2020-01-04 05:09:55
引言 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: yield可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 #yield功能(可以吧函数暂停住,保存原来的状态)-------------- def f1(): print('first') yield 1 print('second') yield 2 print('third') yield 3 # print(f1())

034_协程

强颜欢笑 提交于 2020-01-04 05:09:40
前言   之前我们学习了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位。 按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。   随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。   为此我们需要先回顾下并发的本质:切换+保存状态   cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制), 一种 情况是该任务发生了阻塞, 另外一种 情况是该任务计算的时间过长(每个程序运行一段时间,切换进行)       ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态    一: 其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。    二: 第一种情况的切换。在任务一遇到io情况下,切到任务二去执行,这样就可以利用任务一阻塞的时间完成任务二的计算,效率的提升就在于此。 协程介绍    协程: 是单线程下的并发,又称微线程

第三十二章:协程

拈花ヽ惹草 提交于 2020-01-04 05:09:08
引子 上一节中我们知道GIL锁将导致CPython无法利用多核CPU的优势,只能使用单核并发的执行。很明显效率不高,那有什么办法能够提高效率呢? 效率要高只有一个方法就是让这个当前线程尽可能多的占用CPU时间,如何做到? 任务类型可以分为两种 IO密集型 和 计算密集型 对于计算密集型任务而言 ,无需任何操作就能一直占用CPU直到超时为止,没有任何办法能够提高计算密集任务的效率,除非把GIL锁拿掉,让多核CPU并行执行。 对于IO密集型任务任务,一旦线程遇到了IO操作CPU就会立马切换到其他线程,而至于切换到哪个线程,应用程序是无法控制的,这样就导致了效率降低。 如何能提升效率呢?想一想如果可以监测到线程的IO操作时,应用程序自发的切换到其他的计算任务,是不是就可以留住CPU?的确如此 一、单线程实现并发 单线程实现并发这句话乍一听好像在瞎说 首先需要明确并发的定义 并发:指的是多个任务同时发生,看起来好像是同时都在进行 并行:指的是多个任务真正的同时进行 早期的计算机只有一个CPU,既然CPU可以切换线程来实现并发,那么为何不能再线程中切换任务来并发呢? 上面的引子中提到,如果一个线程能够检测IO操作并且将其设置为非阻塞,并自动切换到其他任务就可以提高CPU的利用率,指的就是在单线程下实现并发。 如何能够实现并发呢 并发 = 切换任务+保存状态,只要找到一种方案

并发编程之协程

流过昼夜 提交于 2020-01-04 05:08:12
目录 协程 什么是协程 线程出现的问题 使用协程的好处 符合什么条件就能称之为协程: 协程的使用场景 Python中对于协程有两个模块,greenlet和gevent。 Greenlet(greenlet的执行顺序需要我们手动控制) gevent(自动切换,由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成) 协程 什么是协程 ​ 在 单个线程下 实现并发效果,在多个任务之间切换。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序中存在大量不需要CPU的操作时(IO),适用于协程。 ​ 官方说法:协程称为微线程,就是操作系统级别的线程。是由操作系统来控制调度的。 线程出现的问题 GIL锁 导致多线程无法并行执行,只能并发执行,效率低。但是并发时我们要实现的最终目的(最好并行) 线程出现假死状态 例如tcp服务器,限制了最大线程数量1000,如果第1000个客户有一部分,没有进行任何的操作,而新任务将无法被处理,即使CPU空闲 使用协程的好处 协程有极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销 不需要多线程的锁机制,因为只有一个线程 ,不存在同时写变量冲突,在协程中控制共享资源不加锁

day38,线程队列,协程

房东的猫 提交于 2020-01-04 05:08:02
协程和断点上传 线程中的队列 我们经常会遇到这样的一个问题,这里有成千上万条数据,每次需要取出其中的一条数据进行处理,那么引入多线程该怎么进行任务分配? 我们可以将数据进行分割然后交给多个线程去跑,可是这并不是一个明智的做法。在这里我们可以使用队列与线程相结合的方式进行任务分配。 队列线程的思想: 首先创建一个全局共享的队列,队列中只存在有限个元素,并将所有的数据逐条加入到队列中,并调用队列的join函数进行等待。之后便可以开启若干线程,线程的任务就是不断的从队列中取数据进行处理就可以了。 from queue import Queue,LifoQueue,PriorityQueue # 与进程中的Joinablequeue 使用方式一模一样 但是 不具备IPC # q = Queue() # q.put("123") # q.put("456") # print(q.get()) # print(q.get()) # # print(q.get(block=True,timeout=3)) # q.task_done() # q.task_done() # q.join() # print("over") # last in first out 后进先出 先进 后出 模拟堆栈 ====================================================