Leer desde dos puertos seriales de forma asíncrona.

Me gustaría leer desde dos (o más) puertos seriales (/ dev / ttyUSB0, etc.) al mismo tiempo en Python en Linux. Quiero leer las líneas completas de cada puerto (el que tenga datos) y procesar los resultados en el orden recibido (sin condiciones de carrera). Como un simple ejemplo, simplemente podría escribir las líneas en un solo archivo combinado.

Supongo que la forma de hacerlo se basa en pyserial, pero no puedo averiguar cómo hacerlo. Pyserial tiene lecturas sin locking usando asyncio y usando hilos . Asyncio está marcado como experimental. Supongo que no habría condiciones de carrera si el procesamiento se realiza en asyncio.Protocol.data_received() . En el caso de subprocesos, el procesamiento probablemente tendría que estar protegido por un mutex.

Tal vez esto también se puede hacer no en pyserial. Los dos puertos serie se pueden abrir como archivos y luego leerlos cuando los datos están disponibles utilizando select() .

Según lo sugerido por @AlexHall en un comentario, aquí hay una solución que usa un hilo para cada puerto serie y una cola para sincronizar el acceso:

 import serial import Queue import threading queue = Queue.Queue(1000) def serial_read(s): while True: line = s.readline() queue.put(line) serial0 = serial.Serial('/dev/ttyUSB0') serial1 = serial.Serial('/dev/ttyUSB1') thread1 = threading.Thread(target=serial_read, args=(serial0,),).start() thread2 = threading.Thread(target=serial_read, args=(serial1,),).start() while True: line = queue.get(True, 1) print line 

Puede ser posible escribir esto con más elegancia, pero funciona.

Considere el uso de aioserial .

Aquí hay un ejemplo:

 import asyncio import concurrent.futures import queue import aioserial async def readline_and_put_to_queue( aioserial_instance: aioserial.AioSerial, q: queue.Queue): while True: q.put(await aioserial_instance.readline_async()) async def process_queue(q: queue.Queue): with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor: while True: line: bytes = await asyncio.get_running_loop().run_in_executor( executor, q.get) print(line.decode(errors='ignore'), end='', flush=True) q.task_done() q: queue.Queue = queue.Queue() aioserial_ttyUSB0: aioserial.AioSerial = \ aioserial.AioSerial(port='/dev/ttyUSB0') aioserial_ttyUSB1: aioserial.AioSerial = \ aioserial.AioSerial(port='/dev/ttyUSB1', baudrate=115200) asyncio.run(asyncio.wait([ readline_and_put_to_queue(aioserial_ttyUSB0, q), readline_and_put_to_queue(aioserial_ttyUSB1, q), process_queue(q), ])) 

Podrías intentar tomar los valores en orden y memorizarlos en variables:

 a = data1.read () b = data2.read () 

Y después procesarlo en orden:

 If len (a) != 0 or len (b ) != 0: Process a Process b 

Usando este método si uno o ambos valores tienen datos, procesarlos