英文:
Sampling a Digital Input of a PLC with a rate of 1s makes GUI slow
问题
我已创建一个在Python中从Omron PLC读取布尔值数组的函数。
该函数每秒执行一次,以便检测某个D/I是否发生了变化。
尽管如此,GUI变得较慢。
我使用PYQT作为GUI。
以下是我编写的函数示例:
def read_DI(self):
self.timer = QtCore.QTimer()
self.timer.setInterval(1000) #1秒迭代
self.timer.timeout.connect(lambda: self.read_DI())
if not self.timer.isActive():
self.timer.start()
#读取DI的值
else:
self.timer.stop()
该函数每1秒运行一次,周期性地检测DIs的值是否发生了变化。
每当我运行GUI应用程序并移动GUI窗口时,它会在每1秒卡住一次。
您有没有办法解决这个问题?我担心如果我有一个包含大量要读取的DIs的更大项目,它将变得太慢。
谢谢。
英文:
I have created a function in Python that reads an array of Boolean values from an Omron PLC.
That functions is being execute every one second , in order to sense if a certain D/I has changed.
Although, the GUI becomes slower.
I use PYQT as the GUI.
The following is the example of the function I have written :
def read_DI(self):
self.timer = QtCore.QTimer()
self.timer.setInterval(1000) #1 second iteration
self.timer.timeout.connect(lambda: self.read_DI())
if not self.timer.isActive():
self.timer.start()
#Reading Values of DIs
else:
self.timer.stop()
This function runs every 1 second periodically in order to sense if the value of the DIs have changed.
Whenever I run the GUI application, and move the GUI's window around the desktop, it gets stuck every 1 second.
Do you have any idea how to solve this problem? I'm afraid that if I'll have a bigger project with lots of DIs to read , it would be too slow.
Thanks.
答案1
得分: 0
这里存在一个实现问题。我认为在考虑线程之前,你应该先解决这个问题。
def read_DI(self):
self.timer = QtCore.QTimer()
self.timer.setInterval(1000) #1秒间隔
self.timer.timeout.connect(lambda: self.read_DI())
if not self.timer.isActive():
self.timer.start()
#读取DI的值
else:
self.timer.stop()
第一次调用该函数时,你创建了一个新的Timer()对象并将其绑定到self.timer上。你设置了一个回调,一秒后触发,并启动计时器。然后你从DI中获取数据。
一秒后,函数再次被调用。你创建了第二个新的Timer()对象并将其绑定到self.timer上。你设置了一个回调并启动该计时器。然后你从DI中获取数据。(if语句的第一个分支始终被执行,因为计时器总是新的。你在函数的第一行刚刚创建了它。)
此时,你已经创建了两个QtCore.Timer()对象,但你只有一个Python变量self.timer,并且它绑定到这些计时器的第二个上。第一个Timer发生了什么事?它仍然在运行吗?它仍然每秒触发回调函数read_DI吗?我也不知道,但如果是这样,我不会感到惊讶。每秒你都会创建一个新的计时器。
Qt是一个带有Python包装器的C++库,有时它们以不直观的方式交互。如果你幸运的话,Python会以某种方式垃圾回收多余的计时器并优雅地关闭它们,而不会向你的程序发送额外的read_DI
调用。我不会对此抱有信心。
实现这种特性的正确方式是在另一个地方处理计时器的创建、设置、启动和停止。当所有设置完成时,你的事件处理程序read_DI
应该如下所示:
def read_DI(self):
# 读取DI的值
就是这样。它应该只做一件事,并尽快完成。
接下来我会弄清楚读取DI到底需要多长时间。调用几次time.time()并打印一下应该能给你一些想法。如果这占用了相当大一部分时间,那么现在是时候想想如何编写一个多线程程序了。
英文:
There is an implementation issue here. I think you should fix that before thinking about threading.
def read_DI(self):
self.timer = QtCore.QTimer()
self.timer.setInterval(1000) #1 second iteration
self.timer.timeout.connect(lambda: self.read_DI())
if not self.timer.isActive():
self.timer.start()
#Reading Values of DIs
else:
self.timer.stop()
The first time this function is called, you create a new Timer() object and bind it to self.timer. You set up a callback to occur one second later and start the timer. Then you take data from the DIs.
One second later, the function is called again. You create a second new Timer() object and bind it to self.timer. You set up a callback and start that timer. Then you take data from the DIs. (The first branch of the if statement is always taken, since the Timer is always a new one. You just created it in the function's first line.)
At that point you have created two QtCore.Timer() objects, but you have only one Python variable self.timer, and it is bound to the second of those Timers. What has happened to the first Timer? Is it still running? Is it still making callbacks to read_DI every second? I don't know either, but I wouldn't be surprised if it is. And every second you create another new Timer.
Qt is a C++ library with a Python wrapper around it, and sometimes they interact in ways that are not intuitive. If you're lucky, Python will somehow garbage collect the extra Timers and shut them down gracefully, without bombarding your program with extra calls to read_DI
. I wouldn't bet on it.
The correct way to implement a feature like this is to handle Timer creation, setup, starting and stopping in another place. When that's all set up, your event handler, read_DI, should look like this:
def read_DI(self):
# Reading values of DIs
That's it. It should do one thing, and finish as quickly as possible.
The next thing I would do is figure out how long it really takes to read the DIs. A couple of calls to time.time() and a print statement should give you some idea of that. If it's a significant fraction of a second, then it would be time to figure out how to write a multithreaded program.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论