|
4 | 4 | from qfluentwidgets import DoubleSpinBox |
5 | 5 | from PySide6.QtWidgets import QApplication |
6 | 6 | from ok import Logger, og |
| 7 | +from threading import Event |
7 | 8 |
|
8 | 9 | logger = Logger.get_logger(__name__) |
9 | 10 |
|
@@ -33,6 +34,7 @@ def __init__(self, exit_event): |
33 | 34 | self.pynput_keyboard = None |
34 | 35 | self._thread_pool_executor_max_workers = 0 |
35 | 36 | self.thread_pool_executor = None |
| 37 | + self.thread_pool_exit_event = Event() |
36 | 38 | self.shared_frame = None |
37 | 39 | exit_event.bind_stop(self) |
38 | 40 | self.init_pynput() |
@@ -65,30 +67,66 @@ def on_click(self, x, y, button, pressed): |
65 | 67 | def on_press(self, key): |
66 | 68 | self.pressed.emit(key) |
67 | 69 |
|
68 | | - def get_thread_pool_executor(self, max_workers=4): |
| 70 | + def get_thread_pool_executor(self, max_workers=6): |
69 | 71 | """ |
70 | 72 | 获取全局执行器。 |
71 | | -
|
72 | 73 | 如果请求的 max_workers 大于当前值,将安全地重建线程池。 |
73 | 74 | """ |
74 | 75 | if self.thread_pool_executor is not None and max_workers > self._thread_pool_executor_max_workers: |
75 | 76 | logger.info( |
76 | 77 | f"thread pool max_workers not enough, reset max_workers {self._thread_pool_executor_max_workers} -> {max_workers}") |
77 | | - self.shutdown_task_executor() |
| 78 | + self.shutdown_thread_pool_executor() |
78 | 79 |
|
79 | 80 | if self.thread_pool_executor is None: |
80 | 81 | logger.info(f"create thread pool executor, max_workers: {max_workers}") |
| 82 | + self.thread_pool_exit_event.clear() |
81 | 83 | self.thread_pool_executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) |
82 | 84 | self._thread_pool_executor_max_workers = max_workers |
83 | 85 |
|
84 | 86 | return self.thread_pool_executor |
85 | 87 |
|
86 | 88 | def shutdown_thread_pool_executor(self): |
87 | 89 | if self.thread_pool_executor is not None: |
| 90 | + logger.info("Shutting down thread pool executor...") |
| 91 | + self.thread_pool_exit_event.set() |
88 | 92 | self.thread_pool_executor.shutdown(wait=False, cancel_futures=True) |
89 | 93 | self.thread_pool_executor = None |
90 | 94 | self._thread_pool_executor_max_workers = 0 |
91 | 95 |
|
| 96 | + def submit_periodic_task(self, delay, task, *args, **kwargs): |
| 97 | + """ |
| 98 | + 提交一个循环任务到线程池。 |
| 99 | + 如果要停止循环,任务函数应返回 False。 |
| 100 | + |
| 101 | + :param task: 要执行的函数 |
| 102 | + :param delay: 每次执行后的间隔时间(秒) |
| 103 | + :param args: 位置参数 |
| 104 | + :param kwargs: 关键字参数 |
| 105 | + """ |
| 106 | + executor = self.get_thread_pool_executor() |
| 107 | + |
| 108 | + def loop_wrapper(): |
| 109 | + logger.debug(f"Periodic task {task.__name__} started.") |
| 110 | + |
| 111 | + while not self.thread_pool_exit_event.is_set(): |
| 112 | + should_stop = False |
| 113 | + try: |
| 114 | + if task(*args, **kwargs) is False: |
| 115 | + should_stop = True |
| 116 | + except Exception as e: |
| 117 | + logger.error(f"Error in periodic task {task.__name__}: {e}") |
| 118 | + |
| 119 | + if should_stop: |
| 120 | + logger.debug(f"Periodic task {task.__name__} decided to stop.") |
| 121 | + break |
| 122 | + |
| 123 | + if self.thread_pool_exit_event.wait(timeout=delay): |
| 124 | + logger.debug(f"Periodic task {task.__name__} received stop signal.") |
| 125 | + break |
| 126 | + |
| 127 | + logger.debug(f"Periodic task {task.__name__} stopped.") |
| 128 | + |
| 129 | + executor.submit(loop_wrapper) |
92 | 130 |
|
93 | 131 | if __name__ == "__main__": |
94 | 132 | glbs = Globals(exit_event=None) |
0 commit comments