avatar

AngYi

Aim for the stars, and beyond.

  • 首页
  • 分类
  • 标签
  • 归档
  • 相册
  • 关于我
Home python 协程、async & 异步
文章

python 协程、async & 异步

Posted 2022-04-4 Updated 2023-10- 17
By AngYi
13~17 min read
  • 异步非阻塞
  • fastapi,django asgi --> 提升性能

1. 进程 线程 协程的通俗理解

假设现在有一个工厂生产矿泉水瓶,为了提高生产效率:

  • 多进程,把这个工厂再复制一个,里面的资源,人力都复制一份,同时生产
  • 多线程,在这个工厂里面增加生产流水线,从而提高生产力
  • 协程,不复制工厂,不增加流水线,也不增加工人,让机器工作的同时,提高人员调度效率。比如,拧瓶盖是机器干的事,而贴标签是人干的事。原来是工人等着机器拧完瓶盖,流水线到这里再贴标签。协程就是当机器拧这个水瓶子的瓶盖的时候,工人久跑去另一个水瓶的贴标签。但是还是在这条流水线上(线程里 ),就是让人跑起来增加效率,不能让工人歇着。

2. 协程

协程不是计算机中真实存在的,计算机只提供了线程和进程,协程是程序设计出来的。协程也叫做微线程,它依赖于线程,其宗旨就是在程序等待的时候能够跳转到另一个任务,利用起来这个等待时间。但是它还是这个线程在做。
python 实现协程有以下几种方法:

  • greenlet 早期模块
  • yield 关键字
  • asyncio装饰器(python 3.4)
  • async await关键字(python 3.5) 推荐

greenlet

# pip install greenlet

from greenlet import greenlet
import time


def test1():
    while True:
        print("dancing.....")
        gr2.switch()
        time.sleep(1)

def test2():
    while True:
        print("singing.....")
        gr1.switch()
        time.sleep(1)


gr1 = greenlet(test1)
gr2 = greenlet(test2)

gr1.switch() # 切到1里面  

# 此程序本质是单线程,只是来回跳转,交叉运行而已

gevent

greenlet 封装了yield ,而gevent 封装了greenlet,gevent 遇到延时会自动切换任务。

import gevent  
import time 
from gevent import monkey
monkey.patch_all() # 打补丁 打了补丁之后,time sleep也是可用的


def dancing():
    while True:
        print("dancing.....")
        # time.sleep(1)
        gevent.sleep(1)
        

def singing():
    while True:
        print("singing.....")
        # time.sleep(2)
        gevent.sleep(1)
        

def main():
    g1 = gevent.spawn(singing)
    g2 = gevent.spawn(dancing)

    g1.join()
    g2.join()

if __name__ == '__main__':
    main()

asynicoio 模块

现在更推荐asynicio模块,其使用方法如下:

import asyncio
import time 


async def dancing():
    while True:
        print("dancing.....")
        await asyncio.sleep(1)


async def singing():
    while True:
        print("singing.....")
        await asyncio.sleep(1)

        

async def main():
    task1 = asyncio.create_task(singing())
    task2 = asyncio.create_task(dancing())
    await task1
    await task2
   

if __name__ == '__main__':
    asyncio.run(main())

3. 异步编程

3.1 事件循环

理解成为一个死循环,去检测执行某些代码,一直检测那些任务是可执行的,哪些任务是等待的,哪些任务是执行完的。

import asynicio

loop = asynic.get_event_loop()
loop.run_until_complete(任务)

3.2 快速上手

协程函数 async def
协程对象,执行协程函数()得到的就是协程对象

import asyncio
async def f(): # 协程函数
    pass

result = f() # 协程对象
# ----------- 旧版本中这样运行 ---
loop = asynic.get_event_loop()
loop.run_until_complete(result)

# ------ 在现在的新版本中  -----
asyncio.run(result) #这样执行

3.3 await

async wait ,等待什么呢,等待+可等待对象(协程对象,Future,Task对象 ->IO等待 )

import asyncio

async def func():
    await asyncio.sleep(2) # 可以理解为io等待,这时就会切换任务
    
asyncio.run( func() )
import asyncio

async def others():
    print("start")
    await asyncio.sleep(1)
    print("end")
    return "返回值"


async def main():
    # task1 = asyncio.create_task(others())
    # task2 = asyncio.create_task(others())

    # await task1
    # await task2
    response = await others() # await 就是等待,不会往下走,不会切换
    print('io 请求结果为',response)

    response1 = await others()
    print('io 请求结果为',response1)


asyncio.run(main()) # 这里顺序输出

3.4 task对象

在事件循环中,添加多个任务的。遇到io自动会进行任务切换。
可以让协程加入事件循环中,等待被调用。

import asyncio
import time 


async def dancing():
    while True:
        print("dancing.....")
        await asyncio.sleep(1)


async def singing():
    while True:
        print("singing.....")
        await asyncio.sleep(1)

        

async def main():
    # 创建task对象,将当前执行函数添加到事件循环
    task1 = asyncio.create_task(singing())
    
    # 创建task对象,将当前执行函数添加到事件循环
    task2 = asyncio.create_task(dancing())
    
    # 以上会马上执行完毕,不会等待,因为只是创建对象而已
    
    await task1 # 等待task1  task1执行
    await task2
   

if __name__ == '__main__':
    asyncio.run(main())

示例2:

import asyncio
import time 


async def dancing():
    while True:
        print("dancing.....")
        await asyncio.sleep(1)


async def singing():
    while True:
        print("singing.....")
        await asyncio.sleep(1)

        

async def main():
    task_list = [
        asyncio.create_task(singing()),
        asyncio.create_task(dancing()),
    ]
    await asyncio.wait(task_list)
   
if __name__ == '__main__':
    asyncio.run(main())

3.5 Future对象

更低级的接口,更底层,一般不会用到。
Task 继承 Future对戏那个,Task对象内部await结果的处理是基于Future对象来的。

4. uvloop

是asyncio的事件循环的替代方案。时间循环>默认asyncio的事件循环。

import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

#以下代码与asyncio的编码方式一致

很多支持异步,并宣称非常快的框架,甚至宣称比肩go的原因就是其内部使用了uvloop。

编程语言
python
License:  CC BY 4.0
Share

Further Reading

Oct 15, 2022

Python算发开发项目模版

1. 前言这篇文章主要介绍如何编写有组织的、模块化的和可扩展的python代码。一个机器学习或者深度学习的工程项目,应该像软件开发一样,被视为一个整体。因此,这个项目应该具备这些东西:OOP,TypeChecking,Doc。模块之间遵循设计模式最根本的原则:低耦合高内聚。

Apr 18, 2022

JavaScript基础

JavaScript1. 简介JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明

Apr 4, 2022

python 协程、async & 异步

OLDER

Python 迭代器、生成器

NEWER

Matplotlib常用布局-代码仓库

Recently Updated

  • DeepSeek 创始人梁文峰采访:创新、人才与中国 AI 发展
  • 福州-厦门之行
  • 我有自己的摄影网站啦
  • 借助Ollama一键本地部署CodeGeex,让AI帮你打工
  • Dash 进阶技巧

Trending Tags

ssh linux matlab 感悟 读书 blog git python flask ML

Contents

©2025 AngYi. Some rights reserved.

Using the Halo theme Chirpy