You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Teensy与Python串口通信采样速率过低及数据库优化求助

提升Teensy-Python串口采样率与数据库写入效率的优化方案

嘿,针对你遇到的采样率瓶颈问题,结合你的代码细节,我整理了几个核心优化方向,一步步来解决:

一、先解决Python端串口读取的低效问题

你的Python代码里有几个明显拖慢速度的点:

  1. 频繁的控制台打印:每次循环都打印timechecker和串口数据,控制台IO的速度远低于串口传输和内存操作,这是采样率上不去的头号元凶!先把这些打印注释掉,只在调试时启用。
  2. 串口读取的小细节优化
    • 调整串口参数,设置短超时、关闭不必要的硬件流控,同时调大接收缓冲区,减少阻塞概率:
    • 可以尝试用pyserial内置的read_until(b'\n')替代自定义的ReadLine类,内置方法经过性能优化,可能更高效。

修改后的串口初始化示例:

ser = serial.Serial(
    port='COM5',
    baudrate=2000000,
    timeout=0.001,  # 短超时避免等待
    dsrdtr=False,
    rtscts=False,  # 关闭硬件流控(Teensy USB串口不需要)
    buffer_size=1048576  # 1MB接收缓冲区
)

二、数据库操作的批量优化(最关键的性能提升点)

你现在每次循环都执行2条INSERT+1次COMMIT,数据库的磁盘IO和事务开销极大,这是加入数据库后采样率暴跌的核心原因。优化方案:

  1. 批量插入+延迟提交:攒够N条数据(比如100条)再一次性插入并提交,大幅减少事务次数。
  2. 使用参数化查询:避免字符串格式化的开销,同时防止SQL注入风险。
  3. 合并INSERT语句:利用MySQL支持的批量插入语法,把多条数据合并成一个INSERT语句,减少数据库交互次数。

修改后的数据库操作示例:

# 初始化批量存储列表,设置批量阈值
batch_size = 100
data_batch = []
sync_batch = []

while True:
    # 仅做必要的串口读取,去掉所有非调试打印
    line = rl.readline().decode('utf-8').strip()
    if not line:
        continue
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    
    # 将数据加入批量列表
    data_batch.append( (33.5, current_time, checker) )
    sync_batch.append( (f"http://www.myname.com/value.php?&value={33.5}&time={current_time}", 0) )
    checker += 1
    
    # 达到批量阈值时执行批量插入
    if len(data_batch) >= batch_size:
        # 批量插入tempinfo表
        insert1 = "INSERT INTO tempinfo(value,test,counter) VALUES(%s,%s,%s)"
        cursor.executemany(insert1, data_batch)
        # 批量插入urlsync表
        insert2 = "INSERT INTO urlsync(textvalue,sync) VALUES(%s,%s)"
        cursor.executemany(insert2, sync_batch)
        # 一次性提交事务
        connection.commit()
        # 清空批量列表
        data_batch = []
        sync_batch = []

三、Teensy端的传输优化(从源头减少数据量与解析开销)

当前Teensy每次发送一行文本(比如i的字符串),Python需要做字符串转数字的解析,效率远不如二进制传输:

  1. 改用二进制格式传输:用Serial.write()发送固定长度的字节(比如4字节的int类型),Python直接读取固定字节数后解析,速度更快。
  2. 批量发送数据:攒多个数据后一次性打包发送,减少串口帧的额外开销。

修改后的Teensy代码示例(二进制传输):

int i;
elapsedMillis sinceTest1;
void setup() {
  Serial.begin(2000000);
  i = 0;
  delay(5000);
  Serial.println("Setup Called");
  Serial.flush();
}

void loop() {
  if (i % 500000 == 0) {
    // 定时发送时间戳(保留文本格式方便调试)
    Serial.println(sinceTest1);
  }
  // 发送i的二进制数据(4字节int,小端字节序)
  Serial.write((const uint8_t*)&i, sizeof(i));
  i++;
}

对应的Python读取二进制数据的代码:

# 读取Teensy发送的4字节int数据
def read_int_from_serial(ser):
    data = ser.read(4)
    if len(data) != 4:
        return None
    return int.from_bytes(data, byteorder='little')  # Teensy为小端字节序

# 在循环中替换原readline逻辑
while True:
    val = read_int_from_serial(ser)
    if val is not None:
        # 后续批量插入逻辑...

四、其他小建议

  • 确保使用64位Python版本,并安装最新的pyserialpymysql库,避免旧版本的性能瓶颈。
  • 如果是本地MySQL数据库,可以调整配置(比如增大innodb_buffer_pool_size),提升写入缓存效率。

按照这个顺序优化:先去掉打印、优化串口,再改数据库批量插入,最后考虑二进制传输,采样率应该能大幅提升,甚至接近Arduino串口监视器的水平。

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

火山引擎 最新活动