协程

复制代码
# 协程:
# 协程不是计算机提供的,是程序员认为创造的;也称之为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。
# 主要意义:通过一个线程利用其IO等待事件去做一些其它事情。
# 实现协程的几种方式
#    greenlet    早期的一个模块
#    yield        python关键字
#    asyncio    (py3.4)
#    async、await    python关键字(py3.5)
# 一、greenlet
# 安装
sudo apt-get install greenlet
# 例子: 
from greenlet import greenlet

def func1():
    print(1)    # 第2步输出:1
    gr2.switch()# 第3步切换到func2
    print(2)    # 第6步输出:2
    gr2.switch()# 第7步切换到func2
def func2():
    print(3)    # 第4步输出:3
    gr1.switch()# 第5步切换到func1
    print(4)    # 第8步输出:4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步开始执行func1函数

# 二、yield关键字
def func1():
    yield 1
    yield from func2()
    yield 2
def func2():
    yield 3
    yield 4
f1 = func1()
for item in f1:
    print(item)
    
# 三、asyncio (py3.4及之后版本才自带)
import asyncio

@asyncio.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
    print(2)
@asyncio.coroutine
def func2():
    print(3)
    yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
    print(4)
tasks = [
    asyncio.ensure_future( func1() ),
    asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

# 四、async & await关键字
import asyncio

async def func1():
    print(1)
    await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
    print(2)
async def func2():
    print(3)
    await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
    print(4)
tasks = [
    asyncio.ensure_future( func1() ),
    asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

# 协程的一些概念
# async 关键字
# 协程函数:定义函数时候用 async def 前缀的函数叫协程函数
async def func():
    pass
# 协程对象:执行协程函数得到的协程对象。
result = func()  # 这里func返回的是协程对象,func函数中的代码并不会执行
# 协程函数不是直接调用的,携程函数需要执行的话需要用协程事件去执行
loop = asyncio.get_event_loop()
loop.run_until_complete(result)
asyncio.run( result ) # 这是python3.7及以后版本将上面两句简洁化了一下

# await 关键字
# await + 可等待对象(协程对象、Future、Task对象->io等待)
import asyncio

async def others():  # 定义协程函数
    print('start')
    await asyncio.sleep(2)
    print('end')
    return '返回值'
async def func():    # 定义协程函数
    print('执行协程函数内部代码')
    respose1 = await others() # 等待协程函数执行完成,然后打印返回值
    print('io请求结束,结果为:'+ respose1)
    respose2 = await others()
    print('io请求结束,结果为:'+ respose2)
asyncio.run( func() )

# Task对象
# Task是继承Future
# 创建Task对象的方法:
# asyncio.create_task()
# loop.create_task()
# ensoure_future()
# 例1:传统方式使用Task
async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return '返回值'
async def main():
    print('main开始')
    # 创建Task对象,将当前执行的func函数任务添加到事件循环
    task1 = asyncio.create_task( func() ) # 创建任务前必须先创建事件循环也就是调用asyncio.run
    task2 = asyncio.create_task( func() ) # 创建的时候就自动将任务放进事件循环等待调度
    print('task创建完成')
    await asyncio.sleep(5)
    ret1 = await task1 # 上一行休眠了五秒,在休眠期间task1执行完了的话就直接返回task1任务的执行结果,没有执行完就等待task1任务的执行结果
    print('ret1')
    ret2 = await task2
    print('ret2')
    print(ret1, ret2)
asyncio.run( main() )

# 例2:列表方式
import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return '返回值'
async def main():
    print('main开始')
    # task放到列表中
    task_list = [
        asyncio.create_task( func(), name='t1' ),
        asyncio.create_task( func(), name='t2' ),
    ]
    print('task创建完成')
    done, pendding = await asyncio.wait(task_list, timeout=None) # done是执行后的返回值,pendding就是timeout超时后挂起(没执行完)的任务信息,一般timeout设置为None
    print('done:',done)
    print('pendding:',pendding)
asyncio.run( main() )

# 例3:协程对象列表
import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return '返回值'

task_list = [
    func(),
    func(),
]
done, pendding = asyncio.run( asyncio.wait( task_list ) ) # 这里的task_list不是Task对象而是协程对象,因为这个时候还没有创建事件循环,所以不能用Task对象
print('done:',done)
print('pendding:',pendding)

# asyncio.Future对象
# Task继承的Future,Task对象内容await结果的处理基于Future对象来的。
import asyncio

async def main():
    loop = asyncio.get_running_loop() # 获取当前事件循环对象
    fut = loop.create_future() # 创建一个任务(Future对象),这个任务什么都没干
    await fut # 等待任务执行结果(future对象),没有结果会一直等下去。
asyncio.run( main() )
# 例2:
import asyncio

async def set_after(fut):
    await asyncio.sleep(2)
    fut.set_result('666')
async def main():
    loop = asyncio.get_running_loop() # 获取当前事件循环对象
    fut = loop.create_future()
    await loop.create_task(set_after(fut)) 

    data = await fut  # Future对象
    print(data)
asyncio.run( main() )

# 如果函数不支持await怎么处理
import concurrent.futures 
import time
import asyncio
import threading

def func1():
    print('func1 pid', threading.current_thread().ident)
    time.sleep(3) # 某个耗时操作。如request.get方法不支持asyncio模式,所以只能用线程或进程去实现
    
    return 'sa'
async def main():
    print('main pid', threading.current_thread().ident)
    # 写法一
    loop = asyncio.get_running_loop()
    fut = loop.run_in_executor(None, func1) # 将非协程函数,转换为协程Future对象。因为func1不是协程函数,所以没办法用await关键字去异步执行。run_in_executor方法是将func1放到线程池中去执行,然后将提交到线程池中的函数的返回值转换为asyncio.Future对象。所以func1实际上是开的另一个线程去执行的。
    result = await fut
    print('func1 result:', result)
    # 线程模式
    with concurrent.futures.ThreadPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, func1)
        print('custom thread pool', result)
    # 进程模式
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, func1
        )
        print('costom prosess pool', result)
asyncio.run( main() )

# asyncio 异步迭代器
# 实现__aiter__() 和__anext__()方法对象。
import asyncio
class Reader(object):
    def __init__(self):
        self.count = 0
    async def readLine(self):
        self.count += 1
        if self.count == 100:
            return None
        return self.count
    def __aiter__(self):
        return self
    async def __anext__(self):
        val = await self.readLine() # await 必须卸载async函数内
        if val == None:
            raise StopAsyncIteration
        return val
async def func():
    obj = Reader()
    async for item in obj: # 异步迭代器for循环必须卸载协程函数内
        print(item)
asyncio.run( func() )

# asyncio 异步上下文管理器
import asyncio

class AsyncContextManager:
    def __init__(self, conn):
        self.conn = conn

    async def do_something(self):
        return 666
    
    async def __aenter__(self):
        return self
    
    async def __aexit__(self):
        await asyncio.sleep(2)
async def func():
    async with AsyncContextManager(None) as f: # async with必须在协程方法中
        result = await f.do_something()
        print(result)
asyncio.run(func())

# uvloop
# 是asyncio事件循环的替代方案。uvloop要比python自带的asyncio要快至少两倍。
# 安装:
sudo pip3 istall uvloop
# 如何将asyncio的事件循环替换成uvloop:
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())   # 这里替换原来的事件循环机制
# ......其它代码不变
复制代码

 

posted @   看一百次夜空里的深蓝  阅读(168)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示