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

咨询:Python实现两个并行块循环的最优多线程方案

Python实现并行块循环的最佳方式

先结合你的场景说——从你贴的代码来看,你是在做串口数据读取这类I/O密集型任务,咱来聊聊几种可行的方案,以及哪种最适合你:

我有两个并行块循环,请问使用Python实现它们并行运行的最佳方式是什么?目前我正在通过以下程序试验多线程实现:

#!/usr/bin/env python
import time
import serial
import os
from threading import Thread

ser = serial.Serial(port='/dev/ttyUSB0', baudrate=38400, timeout=None)
ser.flushInput()
ser.flushOutput()

def getstrings(port):
    buf = bytearray()
    while True:
        b = port.read(1)
        if b == b'\x02':
            del buf[:]
        elif b == b'\x03':
            yield buf.decode...

1. 多线程(你的当前方案,最适合你的场景)

你的思路完全没问题!因为串口读取属于I/O阻塞操作,Python的GIL(全局解释器锁)在I/O等待的时候会自动释放,所以多线程能真正实现并行处理,而且开销小、实现简单。我给你完善下代码,把两个循环跑起来:

#!/usr/bin/env python
import time
import serial
from threading import Thread

ser = serial.Serial(port='/dev/ttyUSB0', baudrate=38400, timeout=None)
ser.flushInput()
ser.flushOutput()

def getstrings(port):
    buf = bytearray()
    while True:
        b = port.read(1)
        if b == b'\x02':
            del buf[:]  # 遇到帧头,清空缓存
        elif b == b'\x03':
            try:
                data = buf.decode('utf-8')
                print(f"收到串口数据: {data}")
                buf.clear()
            except UnicodeDecodeError:
                print("数据解码失败,丢弃当前帧")
                buf.clear()
        else:
            buf.extend(b)  # 累积数据

def second_parallel_loop():
    # 这里写你的第二个并行循环逻辑,比如定时打印状态、处理其他I/O任务
    count = 0
    while True:
        print(f"第二个循环运行中,累计次数: {count}")
        count += 1
        time.sleep(1)

if __name__ == "__main__":
    # 启动两个子线程,设置daemon=True让它们随主线程退出
    thread_serial = Thread(target=getstrings, args=(ser,), daemon=True)
    thread_second = Thread(target=second_parallel_loop, daemon=True)
    
    thread_serial.start()
    thread_second.start()
    
    # 让主线程保持运行,直到用户按Ctrl+C终止
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("\n程序终止,关闭串口")
        ser.close()

这里补全了你没写完的解码逻辑,加了异常处理避免崩溃,还设置了守护线程让程序退出更优雅。

2. 多进程(适合CPU密集型任务)

如果你的两个循环里有大量计算(比如复杂的数据解析、数学运算),那多进程会更合适——它能绕过GIL,充分利用多核CPU的优势。不过对于串口这种I/O任务,多进程的开销比线程大很多,而且进程之间不能直接共享串口对象,得用进程间通信或者单独开串口,反而麻烦。简单示例如下:

from multiprocessing import Process

# 函数定义和上面类似,注意进程间资源的问题
if __name__ == "__main__":
    p_serial = Process(target=getstrings, args=(ser,))
    p_second = Process(target=second_parallel_loop)
    
    p_serial.start()
    p_second.start()
    
    p_serial.join()
    p_second.join()

除非你有CPU密集的需求,否则不推荐用这个方案。

3. Asyncio(异步I/O,适合高并发I/O场景)

如果你要同时处理很多I/O任务(比如多个串口、网络请求),异步I/O是更高效的选择——它用单线程实现并发,开销极小。不过需要你的串口库支持异步,比如用pyserial-asyncio这个第三方库:

import asyncio
import serial_asyncio

class SerialAsyncProtocol(asyncio.Protocol):
    def __init__(self):
        self.buf = bytearray()

    def data_received(self, data):
        self.buf.extend(data)
        # 处理帧头帧尾,和之前的逻辑一致
        while b'\x03' in self.buf:
            frame_end_idx = self.buf.index(b'\x03')
            frame_data = self.buf[:frame_end_idx]
            # 找到帧头的位置
            if b'\x02' in frame_data:
                frame_data = frame_data[frame_data.index(b'\x02')+1:]
                try:
                    print(f"异步收到串口数据: {frame_data.decode('utf-8')}")
                except UnicodeDecodeError:
                    print("异步解码失败")
            # 截断缓存,处理下一个帧
            self.buf = self.buf[frame_end_idx+1:]

async def second_async_loop():
    count = 0
    while True:
        print(f"异步第二个循环计数: {count}")
        count += 1
        await asyncio.sleep(1)

async def main():
    loop = asyncio.get_running_loop()
    # 创建异步串口连接
    transport, protocol = await serial_asyncio.create_serial_connection(
        loop, SerialAsyncProtocol, '/dev/ttyUSB0', baudrate=38400
    )
    # 同时运行第二个异步任务
    await asyncio.gather(second_async_loop())

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

这种方式适合高并发场景,但学习成本比线程高,如果只是两个简单的并行循环,线程完全够用了。


总结

结合你的串口读取场景,多线程是最佳选择——实现简单、开销小,完美适配I/O密集型任务的并行需求。如果后续有CPU密集的计算,再考虑多进程;如果要处理大量并发I/O,再尝试asyncio。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:00:33