【问题标题】:asyncio 'function' object has no attribute 'send'asyncio 'function' 对象没有属性 'send'
【发布时间】:2021-03-14 10:57:31
【问题描述】:

我正在尝试每 30 秒向客户端发送一次消息,直到客户端在 django 频道中断开连接。下面是使用 asyncio 编写的一段代码。但是收到错误"AttributeError: 'function' object has no attribute 'send'"。我以前没有使用过 asyncio,所以尝试了很多可能性,所有这些都会导致某种错误(因为我没有经验)。 有人可以帮助我如何解决这个问题。

下面是代码:

class HomeConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name = "home"
        self.room_group_name = self.room_name
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )
        self.accept()
        self.connected = True
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        task = loop.create_task(self.send_response)
        loop.run_until_complete(task)

    async def send_response(self):
        while self.connected:
            sent_by = Message.objects.filter(notification_read=False).exclude(
                last_sent_by=self.scope["user"]).values("last_sent_by__username")

            self.send(text_data=json.dumps({
                'notification_by': list(sent_by)
            }))
            asyncio.sleep(30)

    
    def disconnect(self, close_code):

        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )
        self.connected = False

我认为以下代码部分可能有问题:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
task = loop.create_task(self.send_response)
loop.run_until_complete(task)

使用loop = asyncio.get_event_loop() 而不是创建new_event_loop() 会导致:

RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-0_0'.

【问题讨论】:

  • 您需要loop.create_task(self.send_response())(注意额外的括号),但是代码仍然很有可能无法按照您的意愿工作,因为run_until_complete(顾名思义)阻塞直到给定任务完成。
  • 是的,添加括号有助于调用 send_response 函数。但导致新错误“ RuntimeError: You cannot use AsyncToSync in the same thread as async event loop - just await the async function directly.”
  • 如果您已经在事件循环中运行,也许您应该注意错误消息提供的建议。例如,您可以从AsyncWebsocketConsumer 继承,将connect 设为async def,将代码修改为here,只需await self.channel_layer.group_add(...)。生成 self.send_responseasyncio.create_task(self.send_response()) 不带 run_until_complete
  • 完美。非常感谢您的帮助!

标签: python-3.6 python-asyncio django-channels


【解决方案1】:

我发布这个解决方案作为答案,因为我搜索了很多关于如何在没有客户端在 django-channels 中请求的情况下向客户端发送数据的问题。但找不到任何完整的解释或答案。所以希望这对处于我所处情况的人有所帮助。

感谢 user4815162342 为解决我遇到的问题提供的帮助。

class HomeConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = "home"
        self.room_group_name = self.room_name
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await  self.accept()
        self.connected = True
        try:
            loop = asyncio.get_event_loop()
        except:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
        loop.create_task(self.send_response())

    async def send_response(self):
        while self.connected:
            sent_by = Message.objects.filter(notification_read=False).exclude(
                last_sent_by=self.scope["user"]).values("last_sent_by__username")

            await self.send(text_data=json.dumps({
                'notification_by': list(sent_by)
            }))
            await asyncio.sleep(30)

    async def disconnect(self, close_code):

        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
        self.connected = False

如果有任何问题或过时的用法,请纠正我

【讨论】:

    猜你喜欢
    • 2017-09-28
    • 2021-07-27
    • 2021-08-01
    • 2021-02-17
    • 1970-01-01
    • 2023-01-23
    • 2020-05-21
    • 2019-08-13
    • 2016-03-17
    相关资源
    最近更新 更多