2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

QtのstartTimerによるEventCallbackは、処理がcallback周期から遅れるとどうなるのか確認した際のメモ

Last updated at Posted at 2022-01-09

以下のQtのstartTimerによるEventCallback挙動確認時のメモ

PySide2.QtCore.QObject.startTimer(interval[, timerType=Qt.CoarseTimer])

仕様には特に本件について何か書いているわけではなさそうだ、、
実動作として、timer event callback頻度は1msec周期にしつつ、event処理の中で1000msec sleepを入れてみる。

test.py
# !/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
import time
import datetime
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt, QObject

class MyObject(QObject):

    def __init__(self, parent):
        QObject.__init__(self, parent)

        self.startTimer(1)           # 1-millisecond timer
        #self.startTimer(50)          # 50-millisecond timer
        #self.startTimer(100)         # 1000-millisecond timer
        #self.startTimer(1000)        # 1-second timer
        #self.startTimer(60000)       # 1-minute timer

    def timerEvent(self, event):
        print("Timer ID:", event.timerId())
        print("datetime now:", datetime.datetime.now())
        time.sleep(1)

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.myobject = MyObject(self) 

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

実行したところ、1000msec間隔でevent処理が実行されているようにみえる。
どうやらevent処理中(今回の場合だと、1000msec sleep処理中)は、次のevent callback処理が呼び出されない様子?とりあえず現状動作としてこうだったという事をメモしておく。

$ python test.py
Timer ID: 1
datetime now: 2022-01-09 18:00:46.863970
Timer ID: 1
datetime now: 2022-01-09 18:00:47.866091
Timer ID: 1
datetime now: 2022-01-09 18:00:48.875696
Timer ID: 1
datetime now: 2022-01-09 18:00:49.914547
Timer ID: 1
datetime now: 2022-01-09 18:00:50.921863
Timer ID: 1
datetime now: 2022-01-09 18:00:51.922785
Timer ID: 1
datetime now: 2022-01-09 18:00:52.924472

追記

@tenmyoさんコメントの通り、以下にTimersに関する記載がありました。

Timers | Qt Core 6.2.2
https://doc.qt.io/qt-6/timers.html

For this mechanism to work, the application must run in an event loop. 
You start an event loop with QApplication::exec(). When a timer fires, 
the application sends a QTimerEvent, and the flow of control leaves 
the event loop until the timer event is processed. This implies that a 
timer cannot fire while your application is busy doing something else. 
In other words: the accuracy of timers depends on the granularity of 
your application.

特に以下が気になりイベントループを2つ実行したところ、同じイベントループの他処理に影響しました。
イベントループ内で時間の掛かる処理は別スレッドにするか、別のtimer処理に分ける等、設計する場合は考慮が必要だと思いました。

This implies that a 
timer cannot fire while your application is busy doing something else. 
In other words: the accuracy of timers depends on the granularity of 
your application.

以下の通りMyObjectを2つにしたところ

test.py
# !/usr/bin/python3                                                                                                                                                                                          
# -*- coding: utf-8 -*-                                                                                                                                                                                     

import sys
import time
import datetime
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt, QObject

class MyObject(QObject):

    def __init__(self, parent):
        QObject.__init__(self, parent)

        self.startTimer(1)           # 1-millisecond timer                                                                                                                                                  
        #self.startTimer(50)          # 50-millisecond timer                                                                                                                                                
        #self.startTimer(100)         # 1000-millisecond timer                                                                                                                                              
        #self.startTimer(1000)        # 1-second timer                                                                                                                                                      
        #self.startTimer(60000)       # 1-minute timer                                                                                                                                                      

    def timerEvent(self, event):
        print("Timer ID:", event.timerId(),"  datetime now:", datetime.datetime.now())
        time.sleep(1)

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.myobject = MyObject(self)
        self.myobject2 = MyObject(self)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

1000msec毎にTimer ID: 1のtimerEventTimer ID: 2のtimerEvent、、が順番に返ってきました。

$ python qt.py
Timer ID: 1   datetime now: 2022-01-09 23:14:21.350370
Timer ID: 2   datetime now: 2022-01-09 23:14:22.351786
Timer ID: 1   datetime now: 2022-01-09 23:14:23.353236
Timer ID: 2   datetime now: 2022-01-09 23:14:24.354172
Timer ID: 1   datetime now: 2022-01-09 23:14:25.367485
Timer ID: 2   datetime now: 2022-01-09 23:14:26.367732

参考

PySide2.QtCore.QObject.startTimer(interval[, timerType=Qt.CoarseTimer])

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?