YCQ
YCQ

Reputation: 13

In QThread: calls a function again 1 second after the function finishes

I want to acquire a spectrum of a spectrometer every 1s, and below is the code I wrote for this.

However, when the spectrometer is triggered at less than 1 Hz, the function asking for a spectrum will wait for a trigger and take longer than 1s to process, while the timer has already timed out. This cause the thread to be very laggy and eventually freeze.

What is a better way to write it so that it calls the function 'acquire_spectrum' 1s after the function finishes itself, instead of just calling it every 1s?

class Spec_Thread(QThread):


    def __init__(self):
        QThread.__init__(self)
        self.signals = Signals()
        self.specth = Spectrometer.from_first_available() #connect to the spectrometer
        self.threadtimer = QTimer()
        self.threadtimer.moveToThread(self)
        self.threadtimer.timeout.connect(self.acquire_spectrum)

    def acquire_spectrum(self): #acquire the current spectrum from the spectrometer

        print('in thread,', device_running)
        if device_running == True:
            self.specth.open() #open the usb portal
            self.wavelengths = self.specth.wavelengths() #acquire wavelengths (will wait for a trigger)
            self.intensities = self.specth.intensities() #acquire intensities (will wait for a trigger)
            self.specth.close() #close usb portal
            self.signals.new_spectrum.emit(self.wavelengths, self.intensities)
        else:
            print('Device stopped')
            return



    def run(self):

        self.threadtimer.start(10000)
        loop = QEventLoop()
        loop.exec_()

Upvotes: 1

Views: 92

Answers (1)

eyllanesc
eyllanesc

Reputation: 243907

You have to start a timer after finishing the task execution, and for this you can threading.Timer():

import threading

from PyQt5 import QtCore

import numpy as np

from seabreeze.spectrometers import Spectrometer


class QSpectrometer(QtCore.QObject):
    dataChanged = QtCore.pyqtSignal(np.ndarray, np.ndarray)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.specth = Spectrometer.from_first_available()

    def start(self, repeat=False):
        threading.Thread(target=self._read, args=(repeat,), daemon=True).start()

    def _read(self, repeat):
        self.specth.open()
        wavelengths = self.specth.wavelengths()
        intensities = self.specth.intensities()
        self.specth.close()
        self.dataChanged.emit(wavelengths, intensities)
        if repeat:
            threading.Timer(1, self._read, (repeat,)).start()


if __name__ == "__main__":
    import sys

    app = QtCore.QCoreApplication(sys.argv)
    spectometer = QSpectrometer()
    spectometer.start(True)
    spectometer.dataChanged.connect(print)
    sys.exit(app.exec_())

Upvotes: 1

Related Questions