PySide6 -从DLL到QTableWidget的高数据



我有一个PySide6的python(3.11)项目。应用程序连接到DLL以与其他节点进行CAN通信。作为配置的一部分,在短时间内发送大约50-70条CAN消息(但我为每条消息添加了高达50ms的延迟),仍然会看到数据丢失。

DLL回调函数正确接收来自低级接口驱动程序的所有数据包(在C中完成),如果我尝试直接调用UI元素,我正在接收访问拒绝问题(这很清楚,因为UI似乎在另一个线程中)。

因此我有一个信号,它在每个DLL消息上发出,并将数据传输到UI。如果在发出的UI信号处理程序中,我只使用print()函数打印相同的数据包,则数据将以正确的顺序显示。

# Signal in a class
signal_dll_packet_received = Signal(object)
# Main function called from DLL to process various events
def dll_event_function(self, inpacket):
packet = inpacket.contents
print('DLL PACKET:', packet.data.can_msg)
self.signal_dll_packet_received.emit(packet)
def signal_dll_packet_received_emitted(self, packet):
self.new_ui_window.process_packet(packet)

但是,由于我有一个QTableWidget,我必须执行表搜索记录和更新特定单元格的值。当这样做时,我观察到:

  • 一些数据包在UI中丢失-看起来是因为UI太慢,不能足够快地处理DLL消息。
  • 一些数据包似乎被"覆盖",这意味着即使2个不同的数据包通过DLL到达,UI似乎都是相同的(看起来像相同的指针内存)。

Qt传输"高吞吐量"的正确方法是什么?从DLL到UI的数据,没有数据丢失。

我试过这样做:

  • 对数据包进行深度拷贝并继续拷贝
  • 测试方式删除可能影响性能的tablemodel.beginResetModel()endResetModel()函数。

我应该实现某种环形缓冲区还是有任何推荐的Qt的方式?

新的UI窗口类方法

# method in window class for table manipulation
def process_packet(self, packet):
print('UI PACKET:', packet.data.can_msg)

# DO WORK with data in QTableWidget
# If this is ignored, then it works properly

这里你可以看到DLL包日志打印了几个不同数据的消息,但是UI包(经过emit + table修改),在一个长数据块中,只能看到最后一个DLL包的数据格式->感觉好像内存被覆盖了

开头,顺序是正确的->首先是DLL,然后是UI,再是DLL,然后是UI。后来,它先去几个DLL,然后几个ui,但错误的数据..

DLL PACKET: sec=36913; used=996589; len =  8; data = 01 00 52 41 54 43 4B 4C
UI PACKET: sec=36913; used=996589; len =  8; data = 01 00 52 41 54 43 4B 4C
DLL PACKET: sec=36914; used=027252; len =  8; data = 01 00 45 30 30 31 00 00
UI PACKET: sec=36914; used=027252; len =  8; data = 01 00 45 30 30 31 00 00
DLL PACKET: sec=36914; used=057970; len =  4; data = 02 00 07 00
DLL PACKET: sec=36914; used=087962; len =  4; data = 02 00 02 00
DLL PACKET: sec=36914; used=118081; len =  6; data = 02 00 02 00 03 00
DLL PACKET: sec=36914; used=148968; len =  4; data = 02 00 00 00
DLL PACKET: sec=36914; used=179087; len =  6; data = 02 00 3C 00 14 00
DLL PACKET: sec=36914; used=210279; len =  8; data = 02 00 00 00 00 00 00 00
DLL PACKET: sec=36914; used=240934; len =  4; data = 02 00 00 00
DLL PACKET: sec=36914; used=271181; len =  8; data = 02 00 52 41 54 43 4B 4C
DLL PACKET: sec=36914; used=302253; len =  8; data = 02 00 45 30 30 32 00 00
DLL PACKET: sec=36914; used=332939; len =  4; data = 03 00 0B 00
DLL PACKET: sec=36914; used=362938; len =  4; data = 03 00 03 00
DLL PACKET: sec=36914; used=393082; len =  6; data = 03 00 02 00 03 00
DLL PACKET: sec=36914; used=423929; len =  4; data = 03 00 00 00
DLL PACKET: sec=36914; used=454072; len =  6; data = 03 00 3C 00 14 00
DLL PACKET: sec=36914; used=485224; len =  8; data = 03 00 00 00 00 00 00 00
DLL PACKET: sec=36914; used=516342; len =  4; data = 03 00 00 00
DLL PACKET: sec=36914; used=547190; len =  8; data = 03 00 52 41 54 43 4B 4C
DLL PACKET: sec=36914; used=578189; len =  8; data = 03 00 45 30 30 33 00 00
DLL PACKET: sec=36914; used=608964; len =  4; data = 04 00 17 00
DLL PACKET: sec=36914; used=638963; len =  4; data = 04 00 04 00
DLL PACKET: sec=36914; used=669074; len =  6; data = 04 00 02 00 03 00
DLL PACKET: sec=36914; used=699954; len =  4; data = 04 00 00 00
DLL PACKET: sec=36914; used=730065; len =  6; data = 04 00 14 00 00 00
DLL PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
!!! <- see here -> all UI packets have content from last DLL packet
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
UI PACKET: sec=36914; used=761640; len =  8; data = 04 00 00 00 00 00 00 00
DLL PACKET: sec=36914; used=791959; len =  4; data = 04 00 00 00
UI PACKET: sec=36914; used=791959; len =  4; data = 04 00 00 00
DLL PACKET: sec=36914; used=822167; len =  8; data = 04 00 52 41 54 43 4B 4C
UI PACKET: sec=36914; used=822167; len =  8; data = 04 00 52 41 54 43 4B 4C
DLL PACKET: sec=36914; used=853238; len =  8; data = 04 00 45 30 30 34 00 00
UI PACKET: sec=36914; used=853238; len =  8; data = 04 00 45 30 30 34 00 00

如何解决?

正确的方法是将读取总线与GUI分开,工作线程应该从总线读取并将结果放入队列。

主线程将有一个定时事件(QTimer)读取队列中的数据每…100毫秒,更新屏幕。(只是继续读取队列,直到它为空),

您可以在每次消息到达时发出一个事件,但是每秒对GUI进行70次更新可能很慢,因此计时器将使GUI更具响应性。

这样你就可以确定没有数据丢失,因为每次消息到达时,worker都会被操作系统唤醒。

运行DLL函数会降低GIL,因此额外的线程对应用程序的影响最小。

最新更新