Python 协程(gevent)

协程,又叫微线程,协程是一种用户态的轻量级线程

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的好处:

  无需线程上下文切换的开销
  无需原子操作锁定及同步的开销
  方便切换控制流,简化编程模型
  高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点:

  无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

用yield实现协程

 1 import time
 2 import queue
 3
 4 def consumer(name):
 5     print("--->starting ...")
 6     while True:
 7         new_baozi = yield
 8         print("[%s] is eating baozi %s" % (name, new_baozi))
 9         # time.sleep(1)
10
11 def producer():
12     next(con)
13     next(con2)
14     n = 0
15     while n < 5:
16         n += 1
17         print("\033[32;1m[producer]\033[0m is making baozi %s" % n)
18
19         con.send(n)
20         con2.send(n)
21
22 if __name__ == ‘__main__‘:
23     con = consumer("c1")   #  创建一个生成器对象con
24     con2 = consumer("c2")  #  创建一个生成器对象con2
25     p = producer()         #  执行producer函数,p就是函数返回值

Gevent

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

需要先安装Gevent库

简单测试

 1 from greenlet import greenlet
 2
 3 def test1():
 4     print(12)
 5     gr2.switch()   # 切换
 6     print(34)
 7     gr2.switch()
 8
 9 def test2():
10     print(56)
11     gr1.switch()
12     print(78)
13
14 gr1 = greenlet(test1)
15 gr2 = greenlet(test2)
16
17 gr1.switch()
18
19 ########## 输出 ##########
20 12
21 56
22 34
23 78

另一个例子

gevent.sleep() 模拟IO阻塞

import gevent
import time

def foo():
    print(‘Running in foo‘, time.ctime())
    gevent.sleep(1)
    print(‘Explicit context switch to foo again‘, time.ctime())

def bar():
    print(‘Explicit context to bar‘, time.ctime())
    gevent.sleep(2)
    print(‘Implicit context switch back to bar‘, time.ctime())

gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

输出

Running in foo Thu Oct 20 10:52:58 2016
Explicit context to bar Thu Oct 20 10:52:58 2016
Explicit context switch to foo again Thu Oct 20 10:52:59 2016
Implicit context switch back to bar Thu Oct 20 10:53:00 2016

爬网页

 1 import gevent
 2 import time
 3 from gevent import monkey
 4 monkey.patch_all()
 5 from urllib.request import urlopen
 6
 7
 8 def f(url):
 9     print(‘GET: %s‘ % url)
10     resp = urlopen(url)
11     data = resp.read()
12     print(‘%d bytes received from %s.‘ % (len(data), url))
13
14 l = [‘https://www.python.org/‘, ‘https://www.yahoo.com/‘, ‘https://github.com/‘]
15 start = time.time()
16 # for url in l:
17 #     f(url)
18
19 # gevent.joinall([
20 #     gevent.spawn(f, ‘https://www.pthton.org/‘),
21 #     gevent.spawn(f, ‘https://www.yahoo.com/‘),
22 #     gevent.spawn(f, ‘https://github.com/‘),
23 # ])
24
25
26 gevent.joinall([
27     gevent.spawn(f, ‘https://www.bilibili.com/‘),
28     gevent.spawn(f, ‘http://weibo.com/‘),
29     gevent.spawn(f, ‘http://www.qq.com/‘),
30 ])
31
32 print(time.time() - start)

socket下的gevent

server

 1 import sys
 2 import socket
 3 import time
 4 import gevent
 5
 6 from gevent import socket, monkey
 7
 8 monkey.patch_all()
 9
10
11 def server(port):
12     s = socket.socket()
13     s.bind((‘0.0.0.0‘, port))
14     s.listen(500)
15
16     while True:
17         conn, addr = s.accept()
18         gevent.spawn(handle_request, conn)
19
20
21 def handle_request(conn):
22     try:
23         while True:
24             data = conn.recv(1024)
25             print("recv:", data)
26             conn.send(data)
27             if not data:
28                 conn.shutdown(socket.SHUT_WR)
29                 #break
30
31     except Exception as  ex:
32         print(ex)
33     finally:
34         conn.close()
35
36
37 if __name__ == ‘__main__‘:
38     server(8001)

clinent

 1 import socket
 2
 3 HOST = ‘localhost‘  # The remote host
 4 PORT = 8001  # The same port as used by the server
 5 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 6 s.connect((HOST, PORT))
 7
 8
 9 while True:
10     msg = bytes(input(">>:"), encoding="utf8")
11     s.sendall(msg)
12     data = s.recv(1024)
13     # print(data)
14     print(‘Received‘, str(data,‘utf8‘))
15
16 s.close()
时间: 10-20

Python 协程(gevent)的相关文章

python协程gevent案例:爬取斗鱼美女图片

分析 分析网站寻找需要的网址 用谷歌浏览器摁F12打开开发者工具,然后打开斗鱼颜值分类的页面,如图: 在里面的请求中,最后发现它是以ajax加载的数据,数据格式为json,如图: 圈住的部分是我们需要的数据,然后复制它的网址为https://www.douyu.com/gapi/rknc/directory/yzRec/1,出于学习目的只爬取第一页(减少服务器压力).然后把网址放到浏览器中测试是否可以访问.如图: 结果正常. 分析json数据,提取图片链接 最后分析发现json中的data里面的

python2.0_s12_day9_协程&amp;Gevent协程

Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 协程 1.协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程.(操作系统跟不知道它存在),那你指定协程的实现原理是什么吗? 我们来聊聊协程的实现原理: 首先我们知道多个线程在一个单核CPU上进行并发,它的操作过程是,操作系统能调动的最小单位是线程,当操作系统触发多个线

网络编程之协程——gevent模块

网络编程之协程--gevent模块 gevent模块 安装 pip3 install gevent Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程. Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度. #用法 g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如e

tcp_server_协程gevent版本

#!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2020/1/23 1:50 # @Author : liuyan # @File : test5_tcp_server_5协程gevent版本.py # @Software: PyCharm import gevent from gevent import monkey; monkey.patch_all() #使用此方法,会将代码中检查一遍,如有time.sleep()等延时方法,会

python协程:yield的使用

本文和大家分享的主要是python协程yield相关内容,一起来看看吧,希望对大家学习python有所帮助. 协程定义 协程的底层架构是在pep342 中定义,并在python2.5 实现的. python2.5 中,yield关键字可以在表达式中使用,而且生成器API中增加了 .send(value)方法.生成器可以使用.send(...)方法发送数据,发送的数据会成为生成器函数中yield表达式的值. 协程是指一个过程,这个过程与调用方协作,产出有调用方提供的值.因此,生成器可以作为协程使用

Python 协程总结

Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是之前的. 优点: 极高的执行效率,因为子程序切换而不是线程切换,没有了线程切换的开销: 不需要多线程的锁机制,因为只有一个线程在执行: 如果要充分利用CPU多核,可以通过使用多进程+协程的方式 使用 打开asyncio的源代码,可以发现asyncio中的需要用到的文件如下: 下面的则是接下来要总结的

从python协程理解tornado异步

博客原文地址:http://www.v2steve.com/py_tornado_async.html 刚接触tornado时候最疑惑的问题就是tornado.gen.coroutine是怎么实现的.如何在代码中用同步格式实现异步效果.看了几次源码发现其实就是python协程的一个具体应用.下面从生成器开始,说说tornado的异步. python协程 python利用yield关键字实现生成器,yield就像生化危机里的T病毒,被yield感染的函数都不仅仅是函数,而是一个函数生成器.函数生成

00.用 yield 实现 Python 协程

来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协程的调度完全由用户控制.协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快. 与线程相比,协程更轻量.一个Python线程大概占用8M内

协程:gevent模块,遇到i/o自动切换任务 038

协程 : gevent模块,遇到io自动切换任务 from gevent import monkey;monkey.patch_all() # 写在最上面 这样后面的所有阻塞就全部能够识别了 import gevent # 直接导入即可 from threading import current_thread import time def eat(name): print('%seat1'% name) # gevent.sleep(2) time.sleep(2) # 加上monkey就能

Python核心技术与实战——十五|Python协程

我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多进程模型,这就是解决并发问题的经典模型之一.在最初的互联网世界中,多线程/多进程就在服务器并发中起到举足轻重的作用. 但是随着互联网的发展,慢慢很多场合都会遇到C10K瓶颈,也就是同时连接到服务器的客户达到1W,于是,很多代码就跑崩溃,因为进程的上下文切换占用了大量的资源,线程也顶不住如此巨大的压力