7Python全栈之路系列之协程

简介:

What is the association?

与子例程一样,协程也是一种程序组件。 相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。 协程源自Simula和Modula-2语言,但也有其他语言支持。 协程更适合于用来实现彼此熟悉的程序组件,如合作式多任务,迭代器,无限列表和管道。

来自维基百科 https://zh.wikipedia.org/wiki/协程


协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的优缺点:

优点

  1. 无需线程上下文切换的开销

  2. 无需原子操作锁定及同步的开销(更改一个变量)

  3. 方便切换控制流,简化编程模型

  4. 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

缺点:

  1. 无法利用多核资源:协程的本质是个单线程,它不能多核,协程需要和进程配合才能运行在多CPU上,当然我们日常所编写的绝大部分应用都没有这个必要,除非是CPU密集型应用。

  2. 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

实现协程实例

yield

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def  consumer(name):
     print ( "--->starting eating baozi..." )
     while  True :
         new_baozi  =  yield   # 直接返回
         print ( "[%s] is eating baozi %s"  %  (name, new_baozi))
         
def  producer():
     =  con.__next__()
     =  con2.__next__()
     =  0
     while  n <  5 :
         + =  1
         con.send(n)   # 唤醒生成器的同时传入一个参数
         con2.send(n)
         print ( "\033[32;1m[producer]\033[0m is making baozi %s"  %  n)
         
if  __name__  = =  '__main__' :
     con  =  consumer( "c1" )
     con2  =  consumer( "c2" )
     =  producer()

Greenlet

安装greenlet

1
pip3 install greenlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# -*- coding:utf-8 -*-
from  greenlet  import  greenlet
 
def  func1():
     print ( 12 )
     gr2.switch()
     print ( 34 )
     gr2.switch()
     
def  func2():
     print ( 56 )
     gr1.switch()
     print ( 78 )
     
# 创建两个携程
gr1  =  greenlet(func1)
gr2  =  greenlet(func2)
gr1.switch()   # 手动切换

Gevent

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

安装Gevent

1
pip3 install gevent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import  gevent
 
def  foo():
     print ( 'Running in foo' )
     gevent.sleep( 2 )
     print ( 'Explicit context switch to foo again' )
     
def  bar():
     print ( 'Explicit context to bar' )
     gevent.sleep( 3 )
     print ( 'Implicit context switch back to bar' )
     
# 自动切换
gevent.joinall([
     gevent.spawn(foo),   # 启动一个协程
     gevent.spawn(bar),
])

页面抓取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from  urllib  import  request
from  gevent  import  monkey
import  gevent
import  time
 
monkey.patch_all()   # 当前程序中只要设置到IO操作的都做上标记
 
def  wget(url):
     print ( 'GET: %s'  %  url)
     resp  =  request.urlopen(url)
     data  =  resp.read()
     print ( '%d bytes received from %s.'  %  ( len (data), url))
     
urls  =  [
     'https://www.python.org/' ,
     'https://www.python.org/' ,
     'https://github.com/' ,
     'https://blog.ansheng.me/' ,
]
 
# 串行抓取
start_time  =  time.time()
for  in  urls:
     wget(n)
print ( "串行抓取使用时间:" , time.time()  -  start_time)
 
# 并行抓取
ctrip_time  =  time.time()
gevent.joinall([
     gevent.spawn(wget,  'https://www.python.org/' ),
     gevent.spawn(wget,  'https://www.python.org/' ),
     gevent.spawn(wget,  'https://github.com/' ),
     gevent.spawn(wget,  'https://blog.ansheng.me/' ),
])
print ( "并行抓取使用时间:" , time.time()  -  ctrip_time)

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
C:\Python\Python35\python.exe E: / MyCodeProjects / 协程 / s4.py
GET: https: / / www.python.org /
47424  bytes received  from  https: / / www.python.org / .
GET: https: / / www.python.org /
47424  bytes received  from  https: / / www.python.org / .
GET: https: / / github.com /
25735  bytes received  from  https: / / github.com / .
GET: https: / / blog.ansheng.me /
82693  bytes received  from  https: / / blog.ansheng.me / .
串行抓取使用时间:  15.143015384674072
GET: https: / / www.python.org /
GET: https: / / www.python.org /
GET: https: / / github.com /
GET: https: / / blog.ansheng.me /
25736  bytes received  from  https: / / github.com / .
47424  bytes received  from  https: / / www.python.org / .
82693  bytes received  from  https: / / blog.ansheng.me / .
47424  bytes received  from  https: / / www.python.org / .
并行抓取使用时间:  3.781306266784668
Process finished with exit code  0









本文转自 Edenwy  51CTO博客,原文链接:http://blog.51cto.com/edeny/1924915,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
传感器 数据采集 监控
Python生成器与迭代器:从内存优化到协程调度的深度实践
简介:本文深入解析Python迭代器与生成器的原理及应用,涵盖内存优化技巧、底层协议实现、生成器通信机制及异步编程场景。通过实例讲解如何高效处理大文件、构建数据流水线,并对比不同迭代方式的性能特点,助你编写低内存、高效率的Python代码。
242 0
|
6月前
|
Linux 数据库 数据安全/隐私保护
Python web Django快速入门手册全栈版,共2590字,短小精悍
本教程涵盖Django从安装到数据库模型创建的全流程。第一章介绍Windows、Linux及macOS下虚拟环境搭建与Django安装验证;第二章讲解项目创建、迁移与运行;第三章演示应用APP创建及项目汉化;第四章说明超级用户创建与后台登录;第五章深入数据库模型设计,包括类与表的对应关系及模型创建步骤。内容精炼实用,适合快速入门Django全栈开发。
313 1
|
7月前
|
数据采集 自然语言处理 Java
Playwright 多语言一体化——Python/Java/.NET 全栈采集实战
本文以反面教材形式,剖析了在使用 Playwright 爬取懂车帝车友圈问答数据时常见的配置错误(如未设置代理、Cookie 和 User-Agent),并提供了 Python、Java 和 .NET 三种语言的修复代码示例。通过错误示例 → 问题剖析 → 修复过程 → 总结教训的完整流程,帮助读者掌握如何正确配置爬虫代理及其它必要参数,避免 IP 封禁和反爬检测,实现高效数据采集与分析。
486 3
Playwright 多语言一体化——Python/Java/.NET 全栈采集实战
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
709 45
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
388 2
|
调度 Python
python知识点100篇系列(20)-python协程与异步编程asyncio
【10月更文挑战第8天】协程(Coroutine)是一种用户态内的上下文切换技术,通过单线程实现代码块间的切换执行。Python中实现协程的方法包括yield、asyncio模块及async/await关键字。其中,async/await结合asyncio模块可更便捷地编写和管理协程,支持异步IO操作,提高程序并发性能。协程函数、协程对象、Task对象等是其核心概念。
249 3
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
150 3
|
NoSQL 关系型数据库 MySQL
python协程+异步总结!
本文介绍了Python中的协程、asyncio模块以及异步编程的相关知识。首先解释了协程的概念和实现方法,包括greenlet、yield关键字、asyncio装饰器和async/await关键字。接着详细讲解了协程的意义和应用场景,如提高IO密集型任务的性能。文章还介绍了事件循环、Task对象、Future对象等核心概念,并提供了多个实战案例,包括异步Redis、MySQL操作、FastAPI框架和异步爬虫。最后提到了uvloop作为asyncio的高性能替代方案。通过这些内容,读者可以全面了解和掌握Python中的异步编程技术。
271 0
|
数据采集 缓存 程序员
python协程使用教程
1. **协程**:介绍了协程的概念、与子程序的区别、优缺点,以及如何在 Python 中使用协程。 2. **同步与异步**:解释了同步与异步的概念,通过示例代码展示了同步和异步处理的区别和应用场景。 3. **asyncio 模块**:详细介绍了 asyncio 模块的概述、基本使用、多任务处理、Task 概念及用法、协程嵌套与返回值等。 4. **aiohttp 与 aiofiles**:讲解了 aiohttp 模块的安装与使用,包括客户端和服务器端的简单实例、URL 参数传递、响应内容读取、自定义请求等。同时介绍了 aiofiles 模块的安装与使用,包括文件读写和异步迭代
375 0
|
数据采集 调度 Python
Python编程异步爬虫——协程的基本原理(一)
Python编程异步爬虫——协程的基本原理(一)
170 0

推荐镜像

更多