由于串行端口通信是异步的,我在涉及与 RS 232 设备通信的项目的早期就发现,我必须有一个后台线程不断读取端口接收的数据。现在,我使用 IronPython (.NET 4.0),因此我可以访问 .NET 中内置的灵活 SerialPort 类。这让我可以编写这样的代码:
self.port = System.IO.Ports.SerialPort('COM1', 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One)
self.port.Open()
reading = self.port.ReadExisting() #grabs all bytes currently sitting in the input buffer
够简单的。但正如我提到的,我希望在新数据到达时不断检查该端口是否有新数据。理想情况下,我会有操作系统tell只要有数据等待,就随时联系我。你知道吗,我的祈祷已经得到回应,有一个DataReceived
提供活动!
self.port.DataReceived += self.OnDataReceived
def OnDataReceived(self, sender, event):
reading = self.port.ReadExisting()
...
可惜这并没有什么价值,因为不保证会引发此事件!
不保证每个接收到的字节都会引发 DataReceived 事件。
那么,回到编写侦听器线程。我很快就完成了这个BackgroundWorker
这只是调用port.ReadExisting()
一遍又一遍地。它会在字节进入时读取字节,并且当它看到行结尾时 (\r\n
),它将读取的内容放入linebuffer
。然后我的程序的其他部分看看linebuffer
查看是否有任何完整的线路等待使用。
现在,这是一个经典生产者-消费者问题,显然。生产者是BackgroundWorker
,将完整的线放入linebuffer
。消费者是一些消耗这些行的代码linebuffer
尽可能快。
然而,消费者的效率有点低。现在他不断地检查linebuffer
,每次发现它是空的都感到失望;虽然每隔一段时间就会发现里面有人排队。优化这一点的最佳方法是什么,以便消费者仅在有空闲线路时醒来?这样消费者就不会不断地转来转去访问linebuffer
,这可能会引入一些并发问题。
另外,如果有一种更简单/更好的方法来不断地从串行端口读取数据,我愿意接受建议!