Asyncio报错:Task got bad yield?udiskie代码运行故障求助
问题排查:udiskie异步代码抛出RuntimeError错误
问题描述
以下代码尝试通过udiskie异步卸载设备,但运行时抛出异常:
import asyncio import udiskie import udiskie.config import udiskie.udisks2 async def main(): device = '/dev/mmcblk0p1' config = udiskie.config.Config.from_file() udisks = await udiskie.udisks2.Daemon.create() await udisks.connect() try: await udisks.unmount(device) finally: await udisks.disconnect() if __name__ == '__main__': asyncio.run(main())
报错信息:
test.py", line 9, in main udisks = await udiskie.udisks2.Daemon.create() File "/usr/lib/python3/dist-packages/udiskie/udisks2.py", line 699, in create proxy = await dbus.connect_service(*service) File "/usr/lib/python3/dist-packages/udiskie/dbus.py", line 288, in connect_service proxy = await proxy_new_for_bus( File "/usr/lib/python3/dist-packages/udiskie/dbus.py", line 279, in proxy_new_for_bus result = await future File "/usr/lib/python3/dist-packages/udiskie/async_.py", line 92, in __await__ return (yield self) RuntimeError: Task got bad yield: <udiskie.async_.Future object at 0x7fbb12c100>
错误原因
核心问题是udiskie自定义的udiskie.async_.Future类与标准库asyncio的Task机制不兼容。udiskie的Future在__await__方法中直接yield self,而asyncio的Task仅支持yield符合标准协议的可等待对象(如asyncio原生Future、Task或协程对象),无法处理这种自定义的yield逻辑。该问题多出现于udiskie版本较旧、异步实现未完全适配asyncio规范的场景。
解决方法
方法1:使用udiskie自带事件循环运行代码
udiskie提供了适配自身异步逻辑的事件循环,替换asyncio.run()即可:
import udiskie import udiskie.config import udiskie.udisks2 from udiskie.async_ import run async def main(): device = '/dev/mmcblk0p1' config = udiskie.config.Config.from_file() udisks = await udiskie.udisks2.Daemon.create() await udisks.connect() try: await udisks.unmount(device) finally: await udisks.disconnect() if __name__ == '__main__': run(main())
方法2:升级udiskie到最新版本
新版本udiskie大概率修复了异步兼容问题,执行升级命令:
# pip安装的版本 pip install --upgrade udiskie # Debian/Ubuntu系统包管理安装的版本 sudo apt install --only-upgrade python3-udiskie
方法3:改用udiskie同步API
若无需异步逻辑,直接使用同步方式操作:
import udiskie import udiskie.config import udiskie.udisks2 def main(): device = '/dev/mmcblk0p1' config = udiskie.config.Config.from_file() udisks = udiskie.udisks2.Daemon() udisks.connect() try: udisks.unmount(device) finally: udisks.disconnect() if __name__ == '__main__': main()
方法4:手动适配udiskie Future到asyncio
若必须依赖asyncio事件循环,可将udiskie自定义Future包装为asyncio兼容对象:
import asyncio import udiskie import udiskie.config import udiskie.udisks2 from udiskie.async_ import Future as UdiskieFuture def udiskie_future_to_asyncio(fut: UdiskieFuture): loop = asyncio.get_event_loop() asyncio_fut = loop.create_future() def on_done(_): try: result = fut.result() asyncio_fut.set_result(result) except Exception as e: asyncio_fut.set_exception(e) fut.add_done_callback(on_done) return asyncio_fut async def main(): device = '/dev/mmcblk0p1' config = udiskie.config.Config.from_file() # 手动处理每个udiskie Future daemon_fut = udiskie.udisks2.Daemon.create() udisks = await udiskie_future_to_asyncio(daemon_fut) connect_fut = udisks.connect() await udiskie_future_to_asyncio(connect_fut) try: unmount_fut = udisks.unmount(device) await udiskie_future_to_asyncio(unmount_fut) finally: disconnect_fut = udisks.disconnect() await udiskie_future_to_asyncio(disconnect_fut) if __name__ == '__main__': asyncio.run(main())
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

