問題描述
這有點長,第一部分只是對問題的描述,第二部分是我的修復"是否正確的問題.
this is a bit longer, the first part is just a description of the problem, the second one the question if my "fix" is correct.
我從 python 編程開始.我創建了一個程序,它與讀取我們熔化實驗室熔爐溫度的 Arduino 進行通信.然后在 PID 算法中使用溫度,并將輸出設置為 Arduino.通信是通過 pyserial 完成的.到目前為止,一切都有效,包括實時繪制溫度信號、PID 變量等.該腳本包括一個主循環和 3 個線程(串行通信、從串行端口讀取的數據移位器、來自 QWidget 的設定溫度和 PID 算法的輸出.這些值用于創建一個數組以在 pyqtgraph 中顯示.最后,第三個線程將數據從 datashifter 轉移到 QWidget.
I started with python programming. I created a program that communicates with an Arduino that reads the temperature of a furnace of our melting lab. The temperature is then used in a PID algorithm and an output is set to the Arduino. The communication is done via pyserial. So far, everthing works, including live plotting of the temperature signals, PID-variables and so on. The script includes a the main loop and 3 threads (serial communication, a datashifter that reads from serialport, the set temperature from the QWidget and the output of the PID algorithm. This values are used to create an array for displaying within pyqtgraph. Finally, the third thread shifts the data from the datashifter to the QWidget.
當使用我的 Linux 筆記本時,一切正常,并且 GUI 從未停止更新.相比之下,當使用任何 Windows 主機時,我會遇到一些 pyqtgraphs 停止刷新的問題.這種行為很奇怪,因為我或多或少地同時設置了所有數據,使用相同的 numpy 數組(只是不同的列)——有些圖刷新時間更長(小時),有些更早停止(分鐘).在搜索了或多或少的漏洞之后 ;-) 我認為我發現了問題:它是從線程到 GUI 的數據傳遞.一些虛擬代碼來解釋發生了什么:
When using my Linux-Notebook, everything works fine, and the GUI never stops updating. In contrast, when using any Windows-Host, i have the problem that some pyqtgraphs stop to refresh. The behavior is strange, because i set all data at more or less the same time, with the same numpy array (just different columns) - some plots refresh longer (hours), some stop earlier (minutes). After searching more or less the hole internet ;-) I think that I found the problem: Its the passing of data from from a thread to the GUI. Some dummy code to explain what's going on:
DataUpdaterToGUI(QThread):
#sets the QWidget from main loop
def setGUI(self, gui):
self.gui = gui
def run()
while True:
with lock(): # RLock() Instance
copyArray = self.dataArray[:] # copy the array from the shifter
self.gui.plot1.copyArray(dataArray[:, 0], copyArray[:, 1])
self.gui.plot2.copyArray(dataArray[:, 0], copyArray[:, 2])
# self.gui.update()
# QApplication.instance().processEvents()
調用 self.gui.update() 和 processEvents() 都不會對結果產生任何影響:繪圖會在一段時間后停止重繪(在 Windows 上).
Neither calling self.gui.update() nor processEvents() has any influence on the outcome: The plots stop redrawing after a while (on windows).
現在我有一個非常簡單的例子,只是想確定我是否正確使用了線程.它工作正常,但我有一些問題:
Now i have a very simple example, and just want to make sure if I'm using the threading-stuff correctly. It works fine, but I have some questions:
- 信號槽方法是否復制傳遞的數據?
- 為什么不需要調用QWidget的update()方法?
- 使用信號時是否必須使用任何類型的鎖?
class Main(QWidget):
def __init__(self):
super().__init__()
self.layout = QGridLayout(self)
self.graph = pg.PlotWidget()
self.graph.setYRange(0,1000)
self.plot = self.graph.plot()
self.layout.addWidget(self.graph,0,0)
self.show()
def make_connection(self, data_object):
data_object.signal.connect(self.grab_data)
@pyqtSlot(object)
def grab_data(self, data):
print(data)
self.plot.setData(data)
class Worker(QThread):
signal = pyqtSignal(object)
def __init__(self):
super().__init__()
def run(self):
self.data = [0, 1]
i = 2
while True:
self.data[1] = i
self.signal.emit(self.data)
time.sleep(0.01)
i += 1
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = Main()
worker = Worker()
widget.make_connection(worker)
worker.start()
sys.exit(app.exec_())
推薦答案
信號槽方法是否復制傳遞的數據? 信號是線程安全的,并且在傳輸數據時會進行復制,所以數據之前的線程和消費它的線程(GUI線程)不會有沖突
Does the signal-slot approach copy the passed data? The signals are thread-safe and when transferring data they make a copy so the thread that precedes the data and the thread that consumes it (GUI Thread) will not have conflicts
為什么不需要調用QWidget的update()方法? 其實pyqtgraph調用的是update方法,plot是一個PlotDataItem,所以如果我們查看setData() 方法,它調用 updateItems() 方法,在該方法中的 setData() 方法曲線 或 scatter 屬性(根據圖形的類型),在曲線的情況 setData() 方法調用 updateData() 和 updateData() 方法調用更新,在分散的情況下,它的 setData() 方法調用 addpoint() 和 addPoints() 調用 invalidate(),而這個 invalidate() 方法調用 update().
Why is it not necessary to call the update() method of the QWidget? Actually pyqtgraph calls the update method, plot is a PlotDataItem, so if we check the source code of setData() method, it calls the updateItems() method, in that method the setData() method of the curve or scatter attribute is called (according to the type of graphics), in the case of curve its setData() method calls updateData(), and the updateData() method calls update, and in the case of the scatter its setData() method calls addpoint(), and addPoints() calls invalidate(), and this invalidate() method calls update().
在使用信號時我必須使用任何類型的鎖嗎?不需要,因為信號是線程安全的,所以 Qt 已經設置了保護以避免沖突.
Do I have to use any kind of locks when using signals? No, as the signals are thread-safe so Qt already has the guards set to avoid the collision.
這篇關于使用 pyqtgraph 和線程的實時繪圖的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!