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.
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.