You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python报错'object has no attribute asyncio',WebSocket节点通信及OOP疑问

问题解决思路

一、报错原因与直接修复

你遇到的Python object has no attribute 'asyncio'错误,是因为代码错误地把asyncio当成了Kern实例的属性调用。asyncio是全局导入的模块,不是k1对象的属性;同时线程的target不能直接传入异步函数,需要用asyncio.run()包裹异步方法,但写法要规范。

错误代码示例:

leader_heartbeat = threading.Thread(target=k1.asyncio.run(node_heartbeat))

正确写法是先定义普通函数作为线程目标,在函数内部执行异步方法:

def run_leader_heartbeat():
    asyncio.run(k1.node_heartbeat())

leader_heartbeat = threading.Thread(target=run_leader_heartbeat)

follower线程同理:

def run_follower_heart():
    asyncio.run(k1.connect_follower_heart())

follower_thread = threading.Thread(target=run_follower_heart)

二、关于是否放弃OOP

完全不用放弃OOP。你把节点核心逻辑(心跳、文件下载、请求处理)封装到Kern类里的设计是合理的,问题出在异步函数与线程结合的写法错误,和OOP本身无关。坚持OOP能让代码结构更清晰,后续扩展功能也更便捷。

三、完整修改后的代码

import boto3
import os
import requests
from botocore.handlers import disable_signing
import asyncio
import websockets
from botocore.exceptions import ClientError
import logging
from azure.storage.blob import BlobServiceClient
from flask import Flask, request
import time
import threading

ID = "xxxx"
device_name="node1"
loop=0

app = Flask(__name__)
# @app.route('/post', methods=['POST'])
class Kern:
    def __init__(self):
        self.leader=0
        self.loop=0

    def download_blob_to_file(self,blob_service_client: BlobServiceClient, container_name, blob):
        blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob)
        with open(file=os.path.join('/home/tian0138/csci-5105/Research', blob), mode="wb") as sample_blob:
            download_stream = blob_client.download_blob()
            sample_blob.write(download_stream.readall())
    
    def handle_post_request(self,response):
        # Get the data from the request body
        ID = response["ID"]
        container = response["container"]
        blob = response["blob"]
        account_name = response["account_name"]
        account_url = "https://{}.blob.core.windows.net".format(account_name)
        blob_service_client = BlobServiceClient(account_url=account_url)
        self.download_blob_to_file(blob_service_client,container,blob)
        # Process the data...
        return 'Success'

    def boot(self):
        url = 'http://localhost:8000/post'
        data = {"ID": ID, "device_name": device_name}
        response = requests.post(url, data=data)
        response = response.json()
        print(response)
        self.handle_post_request(response)

    async def node_heartbeat_response(self,websocket):
        async for message in websocket:
            components=message.split('!')
            if len(components)==1:#ping
                ping=components[0]
                print(ping)
                response="pong"
            else:
                response="wrong"
            await websocket.send(response)

    async def node_heartbeat(self):#leader send 
        await asyncio.sleep(2)  # 用asyncio.sleep替代time.sleep,避免阻塞事件循环
        async with websockets.connect("ws://localhost:8765",ping_interval=None) as websocket:
            await websocket.send("ping") 
            result = await websocket.recv()
            print(result)

    async def connect_follower_heart(self):# 
        async with websockets.serve(self.node_heartbeat_response, "localhost", 8765,ping_interval=None):
            await asyncio.Future()  # run forever

k1=Kern()
k1.boot()
decision = input("Leader?")

def run_leader_heartbeat():
    asyncio.run(k1.node_heartbeat())

def run_follower_heart():
    asyncio.run(k1.connect_follower_heart())

if decision=="leader":
    print("in leader")
    k1.leader=1
    leader_heartbeat = threading.Thread(target=run_leader_heartbeat)
    leader_heartbeat.start()
    leader_heartbeat.join()
else:
    follower_thread = threading.Thread(target=run_follower_heart)
    follower_thread.start()
    follower_thread.join()

四、额外注意事项

  • 修正了变量名拼写错误:bolb改为blob,避免后续出现变量未定义问题。
  • 把node_heartbeat里的time.sleep(2)换成await asyncio.sleep(2),异步函数中用time.sleep会阻塞整个事件循环,破坏异步逻辑。
  • 移除了原代码中无限循环的while True,它会占用主线程导致线程join()无法执行,改为直接等待对应线程结束。
  • 你的Flask实例app未启动,如果boot方法调用的http://localhost:8000/post是该Flask服务,需要在合适位置添加app.run(host='0.0.0.0', port=8000)(注意不要和WebSocket端口冲突)。

内容的提问来源于stack exchange,提问作者Minrui Tian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:47:02