一、并发的本质

切换+保存状态
cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长时间片到了

二、协程

协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)
 

三、协程的优缺点

对比操作系统控制线程的切换,用户在单线程内控制协程的切换
优点如下:
#1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
#2. 单线程内就可以实现并发的效果,最大限度地利用cpu
缺点如下:
#1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
#2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
 

四、协程的特点

1. 必须在只有一个单线程里实现并发
2. 修改共享数据不需加锁
3. 用户程序里自己保存多个控制流的上下文栈
4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
  (协程:本质是一个线程,能够在多个任务切换节省IO时间,任务切换耗时短,协程任务切换由程序完成)
 

五、在任务中切换的例子

  • def consumer():
    while True:
    x = yield
    print('deal:',x) def producer():
    c = consumer()
    next(c)
    for i in range(10):
    print('generate:',i)
    c.send(i)
    producer()

六、greenlet

  1. 简单实例

    #使用greenlet实现任务切换
    from greenlet import greenlet def eat():
    print('eat start')
    g2.switch()
    print('eat end')
    g2.switch() def play():
    print('playing start')
    g1.switch()
    print('playing end') g1 = greenlet(eat)
    g2 = greenlet(play)
    g1.switch()
  2. 实例的执行顺序

七、gevent

  1. gevent

    Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
  2. 简介
    g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的
    
    g2=gevent.spawn(func2)
    
    g1.join() #等待g1结束
    
    g2.join() #等待g2结束
    
    #或者上述两步合作一步:gevent.joinall([g1,g2])
    
    g1.value#拿到func1的返回值
  3. 例子1
    #如果没有遇到能识别的IO操作,不会进行任务切换,实现并发效果
    #要加上from gevent import monkey;monkey.patch_all()
    from gevent import monkey;monkey.patch_all()
    import gevent,time def eat():
    print('eat start')
    time.sleep(1)
    print('eat end') def play():
    print('playing start')
    time.sleep(1)
    print('playing end') g1 = gevent.spawn(eat)
    g2 = gevent.spawn(play) g1.join()
    g2.join()
  4. 例子2
    #我们可以用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程
    from gevent import monkey;monkey.patch_all()
    import threading
    import gevent
    import time def eat():
    print(threading.current_thread().getName())
    print('eat food 1')
    time.sleep(2)
    print('eat food 2') def play():
    print(threading.current_thread().getName())
    print('play 1')
    time.sleep(1)
    print('play 2') g1=gevent.spawn(eat)
    g2=gevent.spawn(play)
    gevent.joinall([g1,g2])
    print('主')
  5. 同步、异步效果
    from gevent import monkey;monkey.patch_all()
    import gevent
    import time def task():
    time.sleep(1)
    print(123) def synchronouse():
    for i in range(10):
    task() def asynchronouse():
    g_lst=[]
    for i in range(10):
    g = gevent.spawn(task)
    g_lst.append(g)
    gevent.joinall(g_lst) synchronouse()
    print('---')
    asynchronouse()
  6. 例子-获取网站源码
    from gevent import monkey;monkey.patch_all()
    import requests
    import gevent url = ['http://www.baidu.com',
    'http://www.sogou.com',
    'http://www.hao123.com',
    'http://www.taobao.com',
    'http://www.cnblog.com'] def get_url(url):
    res = requests.get(url)
    content = res.content
    return len(content) g_lst = []
    for i in url:
    g_lst.append(gevent.spawn(get_url,i)) gevent.joinall(g_lst) for i in g_lst:
    print(i.value)

python 协程 greenlet gevent的更多相关文章

  1. Python 协程(gevent)

    协程,又叫微线程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈.因此: 协程能保留上 ...

  2. python 协程库gevent学习--gevent数据结构及实战(四)

    一不留神已经到第四部分了,这一部分继续总结数据结构和常用的gevent类,废话不多说继续. 1.Timeout错误类 晚上在调试调用第三方接口的时候,发现有些接口耗时非常多,觉得应该有个超时接口来限制 ...

  3. 线程队列 concurrent 协程 greenlet gevent

    死锁问题 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...

  4. python协程初步--gevent库使用以及解释什么是猴子补丁monkey_patch

    协程工作的特点是遇到阻塞或耗时的任务时就切换,协程的生存依赖于线程,线程依赖于进程 一个似乎有点问题的例子 import gevent,time def kisscpc(num): for i in ...

  5. day 34 线程队列 线程池 协程 Greenlet \Gevent 模块

    1 线程的其他方法 threading.current_thread().getName()    查询当前线程对象的名字 threading.current_thread().ident      ...

  6. python 协程库gevent学习--gevent数据结构及实战(三)

    gevent学习系列第三章,前面两章分析了大量常用几个函数的源码以及实现原理.这一章重点偏向实战了,按照官方给出的gevent学习指南,我将依次分析官方给出的7个数据结构.以及给出几个相应使用他们的例 ...

  7. python 协程库gevent学习--源码学习(一)

    总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...

  8. python 协程库gevent学习--gevent源码学习(二)

    在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...

  9. 【python】-- 协程介绍及基本示例、协程遇到IO操作自动切换、协程(gevent)并发爬网页

    协程介绍及基本示例 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他 ...

随机推荐

  1. AOJ 0121 Seven Puzzle {广度优先搜索}(*)

    原题 题意 题意是有一个输入,比方: 1 0 2 3 4 5 6 7 摆成例如以下形状: 1 0 2 3 4 5 6 7 0表示空格.其它数字能够移动到0的位置.最后须要到例如以下形状: 0 1 2 ...

  2. 高速学会Mac上托管代码到github(具体解释)

    之前最開始的时候就一直在github浏览下载各种代码,然后弄了一下代码上传不知道咋弄就不了了之了.刚好近期有空余时间就研究了下github托管代码,这里就具体说说怎样高速的学会github上传你的代码 ...

  3. 解决TortoiseGit下载代码每次要输入用户名、密码

    解决办法: 方案1: 右键>ortoiseGit → Settings → Git → Credential 设置为 wincred - this repository only 或者 winc ...

  4. 【cl】java变量

    知识点一: 变量:有声明,有初始化! 变量作用域:变量在声明的地方开始,到块结束(其中一对{}叫块) 变量不能重复声明(声明=定义):在同一个作用域中不能重复声明变量! 在作用域中如果已经有变量了,就 ...

  5. luogu1967 货车运输 最大瓶颈生成树

    题目大意 给出一张图,给出q对点,求这两个点间权值最小边最大的路径,输出这个最小边权. 题解 我们先一条一条边建图.当建立的边使得图中形成环时,因为环中的每个节点只考虑是否连通和瓶颈大小,要想互相连通 ...

  6. udev详解【转】

    本文转载自:http://blog.csdn.net/skyflying2012/article/details/9359185 如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Li ...

  7. hdoj--迷宫问题

    迷宫问题 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total Submiss ...

  8. 【转】ios蓝牙开发学习笔记(四)ios蓝牙应用的后台处理 -- 不错

    原文网址:http://dev.ailab.cn/article-1038-220511-1.html 默认情况下,当应用进入后台或挂起时,蓝牙任务是不执行的.但是,你可以把应用声明为支持蓝牙后台执行 ...

  9. 18.29SSM基础整合开发

    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/d ...

  10. k8s Job、Cronjob 的使用

    Job负责处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束.而CronJob则就是在Job上加上了时间调度. Job 我们用Job这个资源对象来创建一个任务,我们定一个Job来 ...