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
相关产品推荐
相关产品推荐

