【问题标题】:asyncio - launching infinite loop.create_connection()asyncio - 启动无限循环.create_connection()
【发布时间】:2018-11-20 04:34:26
【问题描述】:

我一直在尝试创建无穷无尽的客户端实例链。

我正在开发一个 asyncio 应用程序,这个应用程序以及许多其他应用程序,例如使用 loop.create_server() 运行服务器,需要每 10 秒连接到服务器列表、发送一些数据然后断开连接。

我不断收到 2 个错误:“runtimeError:事件循环正在运行。”或“asyncio > 任务已销毁,但它处于挂起状态!”

下面的代码有效。

import asyncio
from tcp.client import Client


def send_to_peers(data):
    for index in range(1, 3): #this for-loop just for simulating a list of peers
    try:
        loop = asyncio.get_event_loop()
        coro = loop.create_connection(lambda: Client(), '127.0.0.1', 10000 + index)
        _, proto = loop.run_until_complete(coro)
        msg = data + "-" + str(index) + "\n"
        proto.transport.write(str.encode(msg))
        proto.transport.close()
    except ConnectionRefusedError as exc:
        print(exc)

def infinite():
    for index in range(5): #again this should be a While True:
        #there should be here an asyncio.sleep(10)
        send_to_peers(str(index))

infinite()

但是当我从 main_loop 调用它时,事情开始中断。

async def infinite_loop():
    for index in range(5):
        print("loop n " + str(index))
        task = asyncio.Task(send_to_peers(str(index)))
        await asyncio.sleep(10)
        task.cancel()
        with suppress(asyncio.CancelledError):
            await task

main_loop = asyncio.get_event_loop()
main_loop.run_until_complete(infinite_loop())
main_loop.run_forever()

我尝试将 main_loop 提供给 send_to_peers ,将其提供给 Client(loop) 类,我试图弯腰关闭循环,删除任务,使用奇怪的 ensure_future 组合但没有任何效果。

我尽可能多地用谷歌搜索,我读到嵌套无限循环不好,但我没有找到任何其他方法。

我最后的希望是使用线程,但即使我认为它会起作用,它也不是一个优雅的解决方案,也不是正确的解决方案。

我习惯使用 Node,所以如果我犯了一个愚蠢的错误,请原谅我,我认为 2 周后我可以做到,但现在我来了。

我非常感谢任何帮助。我被困住了。谢谢!

PS: Client() 类非常基础:

import asyncio
import logging
import sys

logging.basicConfig(
    level=logging.DEBUG,
    format='%(name)s > %(message)s',
    stream=sys.stderr
)

class Client(asyncio.Protocol):

    def __init__(self):
        self.log = logging.getLogger('client')
        self.address = None
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport
        self.address = transport.get_extra_info('peername')
        self.log.debug('{}:{} connected'.format(*self.address))

    def data_received(self, data):
            self.log.debug('{}:{} just sent {!r}'.format(*self.address, data))

    def eof_received(self):
        self.log.debug('{}:{} sent EOF'.format(*self.address))

    def connection_lost(self, error=""):
        self.log.debug('{}:{} disconnected'.format(*self.address))
        self.transport.close()

【问题讨论】:

    标签: python async-await python-3.5 infinite-loop python-asyncio


    【解决方案1】:

    我不断收到 2 个错误:“runtimeError:事件循环正在运行。”或“asyncio > 任务已销毁,但它处于挂起状态!”

    如您所见,异步事件循环 do not nest

    要移除嵌套,您应该使用async defsend_to_peers 定义为协程。其中loop.run_until_complete(coro) 应更改为await coro。一旦send_to_peers 是协程,就可以调用它:

    • 来自阻塞代码,例如使用infinite loop.run_until_complete(send_to_peers(...))

    • 来自异步代码,例如 infinite_loop 使用 await send_to_peers(...)

    如果是infinite_loop,可以使用asyncio.wait_for实现超时:

    try:
        await asyncio.wait_for(send_to_peers(str(index)), 10)
    except asyncio.TimeoutError:
        # ... timeout ...
    

    【讨论】:

    • 非常感谢!我完全被困了太久,我非常绝望。今天我测试了它,它就像一个魅力。感谢您告诉我有关 asyncio.wait_for 的信息,这确实成功了!这是有效的 sn-p 代码:pastebin.com/tJEQaBGZ。这个项目是我自己用 Python 做的第一个“不小的”项目,现在它开始工作了,多亏了你!这是一个八卦协议(github.com/CalogeroMandracchia/gossip-protocol),我正处于开发的早期阶段,因为我只能在下班后处理它。再次:谢谢!
    猜你喜欢
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 2012-02-23
    相关资源
    最近更新 更多