import了某些包后,运行asyncio.run()会卡住

import了某些包后,运行asyncio.run()会卡住

问题描述

本人正在用python通过bleak蓝牙连接舵机设备进行控制,由于bleak的connect()函数是async的,我在main函数里通过asyncio.run()来调用,现在问题在于,同样的代码,如果我在main函数前面加入import mediapipe as mp后,运行就会卡住,不会报错也不会输出连接成功的信息。

代码展示

main.py

# main.py

from control_center import ControlCenter

if __name__ == "__main__":

    controlCenter = ControlCenter()
    asyncio.run(controlCenter.servo_controller.connect())
    # controlCenter.servo_controller.connect()
    print (controlCenter.servo_controller.client)
    print (controlCenter.servo_controller.paired)
    print (controlCenter.btmKp)

control_center.py

# control_center.py

import logging

from bt2 import ServoController


class ControlCenter:
    def __init__(self):
        self.count = 0
        self.btmKp = 20
        self.topKp = 20
        self.offsetX = 0
        self.offsetY = 0
        self.offsetDeadBlock = 0.05
        self.lastBtmDegree = 90
        self.lastTopDegree = 90
        # 常量
        self.FRAME_HEAD = 0x55;
        self.FRAME_LENGTH = 0x0b;
        self.FRAME_TYPE = 0x03;
        self.SERVO_NUM = 0x02;
        # 变量
        self.servoId1 = 0x01;
        self.positionLow1 = 0xdc;
        self.positionHigh1 = 0x05;
        self.servoId2 = 0x02;
        self.positionLow2 = 0xdc;
        self.positionHigh2 = 0x05;
        self.servo_controller = ServoController("48:87:2d:62:a5:ae")
        # self.servo_controller.connect()

bt2.py

from bleak import BleakClient

class ServoController:
    def __init__(self, address):
        self.address = address
        self.client = BleakClient(self.address)
        self.paired = False

    async def connect(self):
        print("111")
        await self.client.connect()
        print("222")
        self.paired = await self.client.pair(protection_level=2)
        print(f"Connected: {self.client.is_connected}")
        print(f"Paired: {self.paired}")

    async def disconnect(self):
        await self.client.disconnect()
        print('Disconnected')

    async def send_command(self, command):
        if not self.client.is_connected or not self.paired:
            raise Exception("Not connected or paired.")

        await self.client.write_gatt_char(24, bytes(command))

运行情况

以上代码可以运行,结果如下

img

但在main.py加入import mediapipe as mp后,即使没有任何地方使用,也会一直卡住不会继续执行,也不会报错或退出程序。

img

mediapipe库和asyncio之间的兼容性问题吧

问题点:导入mediapipe库卡住
分析:初次运行mediapipe代码可能需要下载模型,且模型在github上,延迟导致卡住.
处理方案: 尝试单独使用mediapipe库,顺利完成mediapipe的demo,再看问题是否解决.

在main.py加入import mediapipe as mp后,即使没有任何地方使用,也会一直卡住不会继续执,这个现象比较明细的可能就是在导入这个包的,或者说加载这个包的时候卡住了。那就要检查下这个包是否安装正确,版本之类、兼容性的问题。其次,有可能在使用了这个包之后,连接出现了问题,我看你上面的代码在打印了111之后有个await self.client.connect()的操作,也有可能是一直在等待连接,又连接不上

可能多个包之间存在兼容性问题

这可能是因为bleak蓝牙连接的操作需要消耗大量的计算资源,而导致程序阻塞。

修改包的版本试试

基于new bing部分指引作答:
这可能是由于在asyncio.run()函数中使用了asyncio事件循环,并且在该事件循环中的某些任务被阻塞,导致整个程序卡住。可能的原因是mediapipe库的导入和asyncio.run()之间存在一些冲突或不兼容性。

有几种方法可以尝试解决这个问题:

异步导入:尝试使用importlib库进行异步导入mediapipe,以便不会阻塞主事件循环。可以将import mediapipe as mp替换为以下代码:

import importlib
import asyncio

async def import_mediapipe():
    global mp
    mp = importlib.import_module('mediapipe')

async def main():
    await import_mediapipe()
    controlCenter = ControlCenter()
    await controlCenter.servo_controller.connect()
    print(controlCenter.servo_controller.client)
    print(controlCenter.servo_controller.paired)
    print(controlCenter.btmKp)

asyncio.run(main())

然后尝试运行修改后的代码,看看是否仍然会卡住。

使用异步调用:将controlCenter.servo_controller.connect()修改为await controlCenter.servo_controller.connect(),并将main()函数定义为异步函数。修改后的代码如下:

import asyncio

from control_center import ControlCenter

async def main():
    controlCenter = ControlCenter()
    await controlCenter.servo_controller.connect()
    print(controlCenter.servo_controller.client)
    print(controlCenter.servo_controller.paired)
    print(controlCenter.btmKp)

if __name__ == "__main__":
    asyncio.run(main())

然后尝试运行修改后的代码,看看是否仍然会卡住。

调整代码结构:如果以上方法仍然无效,可以尝试重新组织代码结构,将mediapipe的导入放在asyncio.run()之前,或将mediapipe的导入放在单独的函数中,在需要使用它的地方再导入。这样可以避免mediapipe的导入对asyncio.run()的影响。
希望其中一种方法能够解决你的问题。

第一:卡住有可能是get请求的服务端响应超时,通常需要设置一个请求的超时时间:timeout。
第二:三次请求,只出现了两次结果,debug时正常:这也许是终端输出的问题,请求没有丢失,是协程跑的太快了,终端输出有时候不会全部打印,加个time.sleep(0.1)的话,应该可以看到所有请求都执行了的。(多进程时,也是这样的)
第三:bug报错的是“KeyError”,可以肯定的是,取值的时候没有对应key,报错中看不到具体的报错代码,无法推断!