PyQt thread execution timeout in the background

When I click the minimize button to perform this operation in the background,Threads often execute beyond the limited time, Waking up the program in the background is back to normal. Please be patient, it will appear in about a minute.

83EABA78-8324-4105-9E6F-0ADD2998CBC5

EFB3D59A-54C5-4D3E-8128-C303C2774578

import sys, random, time, functools
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMainWindow, QHBoxLayout
from PyQt5.QtCore import QThread, QObject

def clock(func):
    @functools.wraps(func)
    def clocked(*args, **kwargs):
        t0 = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - t0
        name = func.__name__
        l_arg = []
        if args:
            l_arg.append(', '.join(repr(arg) for arg in args))
        arg_str = ', '.join(l_arg)
        print('[%0.5fs] %s(%s)' % (elapsed, name, arg_str))
        return result
    return clocked

@clock
def go_sleep(sleep_time):
    time.sleep(sleep_time)

def go_run():
    for i in range(100):
        go_sleep(random.randint(1, 3))

class WorkThread(QObject):
    def __int__(self):
        super(WorkThread, self).__init__()

    def run(self):
        go_run()

class WinForm(QMainWindow):
    def __init__(self, parent=None):
        super(WinForm, self).__init__(parent)
        self.button1 = QPushButton('Run')
        self.button1.clicked.connect(self.onButtonClick)
        self._thread = QThread(self)
        self.wt = WorkThread()
        self.wt.moveToThread(self._thread)
        layout = QHBoxLayout()
        layout.addWidget(self.button1)
        main_frame = QWidget()
        main_frame.setLayout(layout)
        self.setCentralWidget(main_frame)

    def onButtonClick(self):
        self.button1.setText('Running')
        self._thread.started.connect(self.wt.run)
        self._thread.start()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = WinForm()
    form.show()
    sys.exit(app.exec_())

Do you mean that the execution of those threads lasts longer than the time given by the name? i.e. a time.sleep(1) lasts more than a single second?

That is actually expected! The time.sleep() method can sleep for longer than requested depending on system activity – if the OS doesn’t return control back to the thread, then the sleep won’t finish. I guess that when you minimize the application the priority of the threads is being reduced.

From the Python documentation

time.sleep ( secs )
Suspend execution of the calling thread for the given number of seconds. The argument may be a floating point number to indicate a more precise sleep time. The actual suspension time may be less than that requested because any caught signal will terminate the sleep() following execution of that signal’s catching routine. Also, the suspension time may be longer than requested by an arbitrary amount because of the scheduling of other activity in the system.

If you don’t want this to happen, you can set the priority on your threads. For a single QThread you can use .setPriority. It looks like the equivalent for a QRunnable is passing priority when starting it on your thread pool (although it says this determines run order so it may be subtley different)

threadpool.start(runnable, priority = 0)

Something worth covering in the book I think!

Hi, martin ,Thank you for answering my question.
I want to simulate I/O operation by Sleep(). I tried many types of priorities but none of them achieved the expected.Which priority should I use?

HighestPriority = 5
HighPriority = 4
IdlePriority = 0
InheritPriority = 7
LowestPriority = 1
LowPriority = 2
NormalPriority = 3
TimeCriticalPriority = 6

self._thread.setPriority(QThread.HighPriority)

I am using macOS, this is related to the operating system, it can work normally in Windows.
setPriority
That doc included this line: “The effect of the priority parameter is dependent on the operating system’s scheduling policy. In particular, the priority will be ignored on systems that do not support thread priorities.”

this is related to the operating system, it can work normally in Windows.

Ah, good to know. I’m wondering if you can use another approach to simulate the IO delay – a sleep is very explicitly saying “do nothing for X”, and perhaps the GIL is getting involved here. An actual IO call (even if slow) might wake up more reliably, since the end-time isn’t known in advanced.

What kind of IO are wanting to test? For API calls there are things like Slowwly for example.

Network I/O with Socket communication, Can you give a small demonstration? thank you very much. :smiley:

This is a promising solution:

 defaults write NSGlobalDomain NSAppSleepDisabled -bool YES