协程

【Python协程的实现】

二次信任 提交于 2019-11-28 07:41:31
原文: http://blog.gqylpy.com/gqy/233 补充 : 数据安全问题 进程: 多个进程操作同一个文件,会出现数据不安全线程: 多个线程操作同一个全局变量,会出现数据不安全 对于共享的数据操作: 如果是 += *= /= -= 操作,都存在数据不安全问题 如果是append,extend,pop,remove操作,就不会出现数据不安全问题协程: 永远不会出现数据不安全问题 因为协程是由程序员控制的,而程序员控制的只能是代码 协程示例代码: # 最简单的协程 a = 0 def fn1(): global a g = fn2() # 拿到生成器 next(g) # 转向fn2函数执行 a += 1 next(g) # 转向fn2函数执行 def fn2(): global a yield a += 1 yield print(fn1()) # Noneprint(a) # 2 1. 协程介绍 协程是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是协程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 1. Python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其它线程运行) 2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换

go4

吃可爱长大的小学妹 提交于 2019-11-28 07:33:19
go4 引用循环 package main const N=3 func main(){ m := make(map[int]*int) for i:=0 ; i<N;i++{ m[i]=&i } for _,v:= range m{ print(*v) } } 0 = 0 -> 2 1 = 1 -> 2 2 = 2 -> 2 0 = 0 -> 3 1 = 1 -> 3 2 = 2 -> 3 ----> 333 最后没i++ 了,就等于3了 0x123 正常输出 package main const N=3 func main(){ m := make(map[int]int) for i:=0 ; i<N;i++{ m[i]=i } for _,v:= range m{ print(v) } } --->012 make() new() make() 创建切片,map,数组,通道 new() 创建自定义对象 make()会初始化,new()不会 锁,for抛协程和函数正常传值 const M = 10 func main(){ m := make(map[int]int) wg := &sync.WaitGroup{} mu := &sync.Mutex{} wg.Add(M) for i:=0 ; i< M;i++{ //go func(){ //go 抛协程 for

go4

让人想犯罪 __ 提交于 2019-11-28 07:33:16
go4 引用循环 package main const N=3 func main(){ m := make(map[int]*int) for i:=0 ; i<N;i++{ m[i]=&i } for _,v:= range m{ print(*v) } } 0 = 0 -> 2 1 = 1 -> 2 2 = 2 -> 2 0 = 0 -> 3 1 = 1 -> 3 2 = 2 -> 3 ----> 333 最后没i++ 了,就等于3了 0x123 正常输出 package main const N=3 func main(){ m := make(map[int]int) for i:=0 ; i<N;i++{ m[i]=i } for _,v:= range m{ print(v) } } --->012 make() new() make() 创建切片,map,数组,通道 new() 创建自定义对象 make()会初始化,new()不会 锁,for抛协程和函数正常传值 const M = 10 func main(){ m := make(map[int]int) wg := &sync.WaitGroup{} mu := &sync.Mutex{} wg.Add(M) for i:=0 ; i< M;i++{ //go func(){ //go 抛协程 for

python中重要的模块--asyncio

本小妞迷上赌 提交于 2019-11-28 06:24:32
asyncio 是python3增加的特性。不过backport到了2.7了。 python 2.7 Develop with asyncio Tasks and coroutines python 3.7 asyncio (org CN ) REF: 一份详细的asyncio入门教程 有大量的例子 python中重要的模块--asyncio 不同线程的事件循环 很多时候,我们的事件循环用于注册协程,而有的协程需要动态的添加到事件循环中。一个简单的方式就是使用多线程。 当前线程创建一个事件循环 ,然后在新建一个线程,在新线程中启动事件循环。 当前线程不会被block 。 详解python异步编程之asyncio(百万并发) 介绍 aiohttp Python异步IO编程之-asyncio协程应用例子 如何真正运行一个协程呢?asyncio 提供了三种机制: (1)asyncio.run() 函数,这是异步程序的主入口,相当于C语言中的main函数。 (2)用await等待协程,比如上例中的 await asyncio.sleep(1) 。再看下面的例子,我们定义了协程 say_delay() ,在main()协程中调用两次,第一次延迟1秒后打印“你好”,第二次延迟2秒后打印“猿人学”。这样我们通过 await 运行了两个协程。 从起止时间,多个协程是 顺序执行 的 (3)通过

flask上下文管理之threading.local

流过昼夜 提交于 2019-11-28 06:11:26
Flask之上下文管理 知识储备之问题情境: request中的参数: 单进程单线程 单进程多线程-->reqeust 会因为多个请求,数据发生错乱.--->可以基于threading.local对象 单进程单线程(多协程)threading.local对象做不到(因为一个线程下多个协程同享一个线程的资源) 解决办法: ​ 自定义类似threading.local对象(支持协程)---保证多协程下数据的安全 先来看一下下面这段代码(支持多线程): # -*- coding: utf-8 -*- """ 1288::{} """ from _thread import get_ident import threading class Local(object): def __init__(self): self.storage = {} self.get_ident = get_ident # 设置值 def set(self, k, v): # 获取线程的唯一标识 ident = self.get_ident() # 通过唯一标识去字典里面取值 origin = self.storage.get(ident) if not origin: origin = {k: v} else: origin[k] = v # 将k,v 保存到 storage中 形式如下 # { # 1023:

什么是协程 ?

孤街浪徒 提交于 2019-11-28 05:00:54
最近更新比较少,内心十分的愧疚,实在是太忙了!向各位读者说句抱歉。 今天要讲的这个东西说实话,我也是今天才知道,一个我们大多数人可能从来都没用过的语法,哪就是传说中的【协程 Coroutine】。 可能你会说,携程谁不知道啊,不就是哪个用来订机票订酒店的软件么,这有什么好学的!这样的话你就错了,此协程非彼携程,可不要傻傻分不清楚喽! 什么是进程和线程 进程是什么 直白地讲,进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程,进程拥有代码和打开的文件资源、数据资源、独立的内存空间。 线程又是什么 线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程,线程拥有自己的栈空间。 线程具有五种状态: 对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元。 无论进程还是线程,都是由操作系统所管理的。 进程和线程的痛点 线程之间是如何进行协作的呢? 最经典的例子就是 生产者/消费者模式 : 若干个生产者线程向队列中写入数据,若干个消费者线程从队列中消费数据。 什么是协程 官方定义如下: A coroutine is a function that can suspend its execution (yield) until the given given YieldInstruction finishes.

5.并发编程协程

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

线程,进程,协程面试知识点

微笑、不失礼 提交于 2019-11-28 04:12:50
2. threading.local的作用? import threading # 创建全局ThreadLocal对象: localVal = threading.local() localVal.val = "Main-Thread" def process_student(): print( '%s (in %s)' % (localVal.val, threading.current_thread().name)) def process_thread(name): #赋值 localVal.val = name process_student() t1 = threading.Thread(target= process_thread, args=('One',), name='Thread-A') t2 = threading.Thread(target= process_thread, args=('Two',), name='Thread-B') t1.start() t2.start() t1.join() t2.join() print(localVal.val) #打印结果: ''' One (in Thread-A) Two (in Thread-B) Main-Thread ''' ''' threading。local()这个方法:用来保存一个全局变量

协程与通道

蓝咒 提交于 2019-11-28 03:59:13
进程:计算机进行资源分配调度的基本单位。且运行在自己内存空间内的独立执行体 (一个应用程序就是运行在机器上的一个进程) 线程:进程内部共享进程内存资源的多个执行体(当一个线程进行IO时,换另一个线程执行) 并行:同一个程序在某个时间点同时运行在多个处理器核心上。 并发:同一时间段内,多个线程执行任务(提高ICU的时间使用率) 协程:根据一个或多个线程的可用性,映射到线程之上(Go tuntime中调度) 同步:进程的多个线程(或者协程)中数据一致 协程工作在相同的地址空间中,所以共享内存(sync包)的方式一定是同步的。(不鼓励使用共享内存的方式来达到同步) Go使用channels来同步协程 当系统调用(IO等待等)当前线程的当前协程被阻塞时,当前线程的其余协程会继续在其它线程上工作。 协程(特别轻量,只有4k) 协程可以运行在多个操作系统线程之间(多个线程之间来回跑。),也可以运行在线程之内(呆在一个线程上面) 两种并发方式: 确定性的(明确定义排序),Go的通道,先发送者后接收者(有先后之分) 非确定性的(加锁/互斥),Java的多线程,随机,谁抢到就是谁的 线程通过关键字go调用一个方法或函数实现(也可以时匿名函数) 在当前线程开始一个同时运行的协程。go sum(a,b) 协程的栈(自己建的)会根据需要进行伸缩,不会出现栈溢出。协程没有返回值 main()

异步爬虫

人走茶凉 提交于 2019-11-28 03:24:28
一 线程池实现异步爬虫 import time import requests from multiprocessing.dummy import Pool start_time = time.time() def get_page(url): print("正在下载:", url) response = requests.get(url) time.sleep(3) print("下载完成", url) return {'url': url, 'content': response.text} urls = [ 'http://www.jd.com', 'https://www.baidu.com', 'https://www.python.org' ] if __name__ == '__main__': # 实例化一个线程对象 pool = Pool(4) # 将列表中每一个列表元素传给get_page进行处理 pool.map(get_page, urls) 使用线程池爬取梨视频数据 import time, re import requests from multiprocessing.dummy import Pool from lxml import etree # 线程池处理的是阻塞较为耗时的操作 start_time = time.time() headers =