In order to prevent from context switching, I want to create a big loop to serve both the network connections and some routines.

Here's the implementation for normal functions:

import asyncio
import time


def hello_world(loop):
    print('Hello World')
    loop.call_later(1, hello_world, loop)

def good_evening(loop):
    print('Good Evening')
    loop.call_later(1, good_evening, loop)

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()

print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)

try:
    # Blocking call interrupted by loop.stop()
    print('step: loop.run_forever()')
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()

Here's the implementation for coroutines:

import asyncio


@asyncio.coroutine
def hello_world():
    while True:
        yield from asyncio.sleep(1)
        print('Hello World')

@asyncio.coroutine
def good_evening():
    while True:
        yield from asyncio.sleep(1)
        print('Good Evening')

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
    print('step: loop.run_until_complete()')
    loop.run_until_complete(asyncio.wait([
        hello_world(),
        good_evening()
    ]))
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()

And the mixed one:

import asyncio
import time


def hello_world(loop):
    print('Hello World')
    loop.call_later(1, hello_world, loop)

def good_evening(loop):
    print('Good Evening')
    loop.call_later(1, good_evening, loop)

@asyncio.coroutine
def hello_world_coroutine():
    while True:
        yield from asyncio.sleep(1)
        print('Hello World Coroutine')

@asyncio.coroutine
def good_evening_coroutine():
    while True:
        yield from asyncio.sleep(1)
        print('Good Evening Coroutine')

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()

print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)
print('step: asyncio.async(hello_world_coroutine)')
asyncio.async(hello_world_coroutine())
print('step: asyncio.async(good_evening_coroutine)')
asyncio.async(good_evening_coroutine())

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()

As you see, each coroutine function has a while loop surrounded. How can I make it like the normal one? I.e. when it is done, call itself after the given delay time, but not just put a loop there.

推荐答案

If you really want to eliminate the while-loop from the coroutines (I'm not sure why you feel that's necessary; it's the most natural way to do what you're trying to do), you can use asyncio.async (or asyncio.ensure_future on Python 3.4.4+) to schedule the coroutine to run again on the next event loop iteration:

import asyncio

@asyncio.coroutine
def hello_world():
    yield from asyncio.sleep(1)
    print('Hello World')
    asyncio.async(hello_world())

@asyncio.coroutine
def good_evening():
    yield from asyncio.sleep(1)
    print('Good Evening')
    asyncio.async(good_evening())

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
    print('step: loop.run_until_complete()')
    asyncio.async(hello_world())
    asyncio.async(good_evening())
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()

Note that you have to switch back to using loop.run_forever() if you do this, since hello_world/good_evening will exit immediately after printing now.

Python-3.x相关问答推荐

在循环访问XML中的多个层时,xml.etree.Elementree Python3解析器不起作用

Python3和请求-超文本标记语言:试图抓取一个网站-没有取回真正的超文本标记语言代码

如何从枚举中获取某个值?

我正在try 从 10*3 矩阵中删除随机值并将其变为 10*2 矩阵

合并两个数据帧并对某些总和进行求和

如何使用Selenium从网站下拉菜单中获取值列表?

从 LeetCode 的 Python 解决方案类中理解关键字 self

在 python f-string 中使用 \u

attrs 将 list[str] 转换为 list[float]

根据另一个数据帧中的位置从主数据帧中提取子序列

使用条件参数为 super() 调用 __init__

Dask 多阶段资源设置导致 Failed to Serialize 错误

从 yahoo Finance python 一次下载多只股票

python 3:如何判断一个对象是否是一个函数?

多个返回函数的列表理解?

在 Python 3 中获取所有超类

如何获得 BeautifulSoup 标签的所有直接子代?

为什么 Python 不能识别我的 utf-8 编码源文件?

我可以替换 Python 中对象的现有方法吗?

使用完整路径激活 conda 环境