长 运行 任务上的 Asyncio

Asyncio on long running task

我昨天刚用 python 3.5 学习了异步。

这是我今天要完成的事情。

import asyncio  
import time
import requests

async def foo():
    """Some Long Running Taks"""
    requests.get("")
    print("foo")

async def bar():
    """Some Quick Task"""
    print("bar")

while True:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.gather(foo(), bar()))
    loop.close()
    time.sleep(2)

#Expected output
"""
>>>bar
>>>bar
>>>bar
>>>bar
>>>bar
>>>foo
and so on
"""

这可以使用 python async/await 吗?

您的 time.sleep() 正在阻塞;你需要使用 asyncio.sleep().

为什么你 运行 你的 loopwhile True 里面?

还要注意 asyncio 只会帮助加速 io-bound 任务(例如从网络获取数据)。它不会帮助您加快 cpu 绑定的任务。为此你需要 threads or multiplrocessing.

看到你已经更新了你的问题,这里是我的回答中的一个小更新:requests 也被阻塞并且不能很好地与 asyncio 一起玩。 aiohttp 的功能相似,但与 asyncio

配合得很好

您的代码中存在一些问题:

  1. requests 不支持 asyncio,请改用 aiohttp

  2. 你的协程只有在循环 运行ning 时才会 运行:在你的代码中只调用 loop.run_until_complete() 一次,并安排很多(短或长)使用 await(或 asycio.ensure_future()loop.create_task())的任务。

这是一个与您尝试做的事情类似的示例:

# make sure to run `pip install aiohttp` first!!!

import asyncio

import aiohttp


async def slow_fetch(delay):
    url = "http://httpbin.org/delay/{}".format(delay)
    print("Getting ", url)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            text = await resp.text()
    print("Got {}, {} chars".format(url, len(text)))


async def quick_loop():
    print("enter quick_loop")
    for i in range(10):
        await asyncio.sleep(1)
        print("quick_loop", i)
    print("exit quick_loop")


loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
    slow_fetch(3),
    slow_fetch(4),
    quick_loop(),
))
loop.close()

这是 ensure_future / create_task 的更好方法: 使用装饰器

def async_wrap(func):
@wraps(func)
async def run(*args, loop=None, executor=None, **kwargs):
    if loop is None:
        loop = asyncio.get_event_loop()
    pfunc = partial(func, *args, **kwargs)
    return await loop.run_in_executor(executor, pfunc)

return run

现在如果你有一个很长的 运行 函数,比如一些使用 requests 的函数,你可以这样做:

@async_wrap
def long_running_function():
    return requests.get(_URL)