Reputation: 1
I have a program that starts five threads. Every single thread says 'Hello World!' to the console. At the end of a thread a callback function should be called. This outputs 'Goodby folks' to the console.
To show that threading works, the runtimes of each individual thread are measured and reported. For comparison, the total running time is measured and reported as well.
The total runtime corresponds to the runtime of the longest-running thread. But the output 'Goodby folks' is missing all five times.
Output looks like:
saying Hello World! took 0.126 s
saying Hello World! took 0.439 s
saying Hello World! took 0.645 s
saying Hello World! took 0.994 s
saying Hello World! took 1.469 s
total runtime is 1.479 s
Please, who can tell me, what's wrong here?
import random
import sys
import time
from typing import Callable
from PyQt5.QtCore import QCoreApplication, QThread, QObject, pyqtSignal
class MeasureRuntime:
def __enter__(self):
self.__start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.__stop = time.perf_counter()
self.elapsed = self.__stop - self.__start
return True
class MyQtThreads(QObject):
def __enter__(self):
self.__running_threads: list = []
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.__waitForThreadsListEmpty()
return True
def __waitForThreadsListEmpty(self):
while self.__running_threads:
for thread in self.__running_threads:
if thread.isFinished():
self.__running_threads.pop(self.__running_threads.index(thread))
def doInThread(self, fn, *args, callback: Callable = None, **kwargs) -> int:
thread = MyQtThread(fn, *args, **kwargs)
if callback:
thread.SIG_FINISHED.connect(callback)
self.__running_threads.append(thread)
thread.start()
return id(thread)
class MyQtThread(QThread):
SIG_FINISHED = pyqtSignal(object)
def __init__(self, fn, *args, **kwargs):
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
def run(self):
ret = self.fn(*self.args, **self.kwargs)
result_info = {"thread_id": id(self), "args": ret}
self.SIG_FINISHED.emit(result_info)
def say_hello():
with MeasureRuntime() as rt:
random.seed()
time.sleep(random.random()*3)
print(f'saying Hello World! took ', end='')
print(f'{rt.elapsed:.3f} s')
def say_adieu(args):
print('Goodby folks')
class Main(QThread):
def __init__(self):
super().__init__()
def run(self):
print()
with MeasureRuntime() as rt:
with MyQtThreads() as threads:
for _ in range(5):
threads.doInThread(say_hello, callback=say_adieu)
print(f'\ntotal runtime is {rt.elapsed:.3f} s')
if __name__ == '__main__':
qcoreapp = QCoreApplication(sys.argv)
thread = Main()
thread.finished.connect(qcoreapp.exit)
thread.start()
qcoreapp.exec()
Upvotes: 0
Views: 48