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

使用asyncio无法同时运行任务:Arduino串口阻塞问题求助

解决Asyncio下串口阻塞与计时并行的问题

你的核心问题是阻塞式的串口读取操作(ard.read())会卡住asyncio事件循环,导致计时任务根本没机会运行。要实现并行,必须用异步的串口IO替代阻塞调用,这里推荐用pyserial-asyncio——这是PySerial官方的异步扩展,完美适配asyncio。

步骤1:安装依赖

pip install pyserial-asyncio

步骤2:完整实现代码

import asyncio
import serial_asyncio

# 计时协程:每秒打印当前计时数
async def timer_task():
    count = 0
    while True:
        print(f"计时: {count}秒")
        count += 1
        await asyncio.sleep(1)

# 串口读取协程:异步等待串口数据
async def serial_read_task(serial_port):
    print("等待串口数据...")
    while True:
        # 异步读取一行数据(也可以用read()指定字节数,这里按行处理更直观)
        data = await serial_port.readline()
        if data:
            print(f"收到串口数据: {data.decode('utf-8').strip()}")

# 主入口
async def main():
    # 创建异步串口连接,替换成你的串口参数
    serial_port = await serial_asyncio.open_serial_connection(
        url='COM3', baudrate=9600
    )[0]
    
    # 同时运行计时和串口读取协程
    await asyncio.gather(
        timer_task(),
        serial_read_task(serial_port)
    )

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

关键说明

  • 用serial_asyncio.open_serial_connection()创建的串口对象,所有读取/写入方法都是异步的(带await),不会阻塞事件循环。
  • asyncio.gather()用来并行调度多个协程,事件循环会在等待串口数据的间隙去执行计时任务,实现真正的并行。
  • 如果你需要读取单个字节而非整行,把readline()换成read(1)即可,同样是异步调用。

为什么原来的代码不行?

普通的pyserial的read()是阻塞式的,一旦调用,整个asyncio事件循环会被卡住,直到串口返回数据——期间其他协程(比如你的计时任务)完全得不到执行机会。只有异步IO操作才能让事件循环在等待资源时切换到其他任务。

内容的提问来源于stack exchange,提问作者Dror Aizik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:53:12