xkits-thread 0.1__tar.gz → 0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xkits-thread
3
- Version: 0.1
3
+ Version: 0.2
4
4
  Summary: Thread module
5
5
  Home-page: https://github.com/bondbox/xthreads/
6
6
  Author: Mingzhe Zou
@@ -16,8 +16,6 @@ Classifier: Programming Language :: Python :: 3
16
16
  Requires-Python: >=3.8
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: xkits-command>=0.2
20
- Requires-Dist: xkits-logger>=0.1
21
19
  Requires-Dist: xkits-lib>=0.1
22
20
 
23
21
  # xthreads
@@ -1,7 +1,7 @@
1
1
  # coding:utf-8
2
2
 
3
3
  from xkits_thread.executor import ThreadPool # noqa:F401
4
- from xkits_thread.executor import hourglass # noqa:F401
4
+ from xkits_thread.executor import hourglass # noqa:F401,H306
5
5
  from xkits_thread.lock import NamedLock # noqa:F401
6
6
  from xkits_thread.task import DaemonTaskJob # noqa:F401
7
7
  from xkits_thread.task import DelayTaskJob # noqa:F401
@@ -1,7 +1,7 @@
1
1
  # coding:utf-8
2
2
 
3
3
  __project__ = "xkits-thread"
4
- __version__ = "0.1"
4
+ __version__ = "0.2"
5
5
  __urlhome__ = "https://github.com/bondbox/xthreads/"
6
6
  __description__ = "Thread module"
7
7
 
@@ -9,7 +9,6 @@ from typing import Optional
9
9
  from typing import Set
10
10
  from typing import Tuple
11
11
 
12
- from xkits_command.actuator import Command
13
12
  from xkits_lib.meter import TimeUnit
14
13
 
15
14
 
@@ -38,35 +37,29 @@ def hourglass(seconds: TimeUnit):
38
37
 
39
38
 
40
39
  class ThreadPool(ThreadPoolExecutor):
41
- '''Thread Pool'''
40
+ """Thread Pool"""
42
41
 
43
42
  def __init__(self, max_workers: Optional[int] = None,
44
43
  thread_name_prefix: str = "work_thread",
45
44
  initializer: Optional[Callable] = None,
46
45
  initargs: Tuple = ()):
47
- '''Initializes an instance based on ThreadPoolExecutor.'''
48
- self.__cmds: Command = Command()
46
+ """Initializes an instance based on ThreadPoolExecutor."""
49
47
  if isinstance(max_workers, int):
50
48
  max_workers = max(max_workers, 2)
51
49
  super().__init__(max_workers, thread_name_prefix, initializer, initargs) # noqa:E501
52
50
 
53
- @property
54
- def cmds(self) -> Command:
55
- '''command-line toolkit'''
56
- return self.__cmds
57
-
58
51
  @property
59
52
  def alive_threads(self) -> Set[Thread]:
60
- '''alive threads'''
53
+ """alive threads"""
61
54
  return {thread for thread in self._threads if thread.is_alive()}
62
55
 
63
56
  @property
64
57
  def other_threads(self) -> Set[Thread]:
65
- '''other threads'''
58
+ """other threads"""
66
59
  current: Thread = current_thread()
67
60
  return {thread for thread in self._threads if thread is not current}
68
61
 
69
62
  @property
70
63
  def other_alive_threads(self) -> Set[Thread]:
71
- '''other alive threads'''
64
+ """other alive threads"""
72
65
  return {thread for thread in self.other_threads if thread.is_alive()}
@@ -4,7 +4,6 @@ from queue import Queue
4
4
  import sys
5
5
  from threading import Lock
6
6
  from threading import Thread
7
- from threading import current_thread # noqa:H306
8
7
  from time import sleep
9
8
  from typing import Any
10
9
  from typing import Callable
@@ -13,16 +12,14 @@ from typing import Optional
13
12
  from typing import Set
14
13
  from typing import Tuple
15
14
 
16
- from xkits_command.actuator import Command
17
15
  from xkits_lib.meter import CountMeter
18
16
  from xkits_lib.meter import StatusCountMeter
19
17
  from xkits_lib.meter import TimeMeter
20
18
  from xkits_lib.meter import TimeUnit
21
- from xkits_logger.logger import Logger
22
19
 
23
20
 
24
21
  class TaskJob():
25
- '''Task Job'''
22
+ """Task Job"""
26
23
 
27
24
  def __init__(self, no: int, fn: Callable, *args: Any, **kwargs: Any):
28
25
  self.__no: int = no
@@ -43,38 +40,38 @@ class TaskJob():
43
40
 
44
41
  @property
45
42
  def id(self) -> int:
46
- '''job id'''
43
+ """job id"""
47
44
  return self.__no
48
45
 
49
46
  @property
50
47
  def fn(self) -> Callable:
51
- '''job callable function'''
48
+ """job callable function"""
52
49
  return self.__fn
53
50
 
54
51
  @property
55
52
  def args(self) -> Tuple[Any, ...]:
56
- '''job callable arguments'''
53
+ """job callable arguments"""
57
54
  return self.__args
58
55
 
59
56
  @property
60
57
  def kwargs(self) -> Dict[str, Any]:
61
- '''job callable keyword arguments'''
58
+ """job callable keyword arguments"""
62
59
  return self.__kwargs
63
60
 
64
61
  @property
65
62
  def result(self) -> Any:
66
- '''job callable function return value'''
63
+ """job callable function return value"""
67
64
  if isinstance(self.__result, Exception):
68
65
  raise self.__result
69
66
  return self.__result
70
67
 
71
68
  @property
72
69
  def running_timer(self) -> TimeMeter:
73
- '''job running timer'''
70
+ """job running timer"""
74
71
  return self.__running_timer
75
72
 
76
73
  def run(self) -> bool:
77
- '''run job'''
74
+ """run job"""
78
75
  try:
79
76
  if self.running_timer.started:
80
77
  raise RuntimeError(f"{self} is already started")
@@ -90,26 +87,26 @@ class TaskJob():
90
87
  self.running_timer.shutdown()
91
88
 
92
89
  def shutdown(self) -> None:
93
- '''wait for job to finish'''
90
+ """wait for job to finish"""
94
91
  while self.running_timer.started:
95
92
  sleep(0.05)
96
93
 
97
94
  def startup(self) -> None:
98
- '''same as run'''
95
+ """same as run"""
99
96
  self.run()
100
97
 
101
98
  def restart(self) -> None:
102
- '''restart job'''
99
+ """restart job"""
103
100
  self.shutdown()
104
101
  self.startup()
105
102
 
106
103
  def barrier(self) -> None:
107
- '''same as shutdown'''
104
+ """same as shutdown"""
108
105
  self.shutdown()
109
106
 
110
107
 
111
108
  class DelayTaskJob(TaskJob):
112
- '''Delay Task Job'''
109
+ """Delay Task Job"""
113
110
  MIN_DELAY_TIME: float = 0.001
114
111
 
115
112
  def __init__(self, delay: TimeUnit, no: int, fn: Callable, *args: Any, **kwargs: Any): # noqa:E501
@@ -123,34 +120,34 @@ class DelayTaskJob(TaskJob):
123
120
 
124
121
  @property
125
122
  def delay_timer(self) -> TimeMeter:
126
- '''job delay timer'''
123
+ """job delay timer"""
127
124
  return self.__delay_timer
128
125
 
129
126
  @property
130
127
  def delay_time(self) -> float:
131
- '''job delay time'''
128
+ """job delay time"""
132
129
  return self.__delay_time
133
130
 
134
131
  @property
135
132
  def waiting(self) -> bool:
136
- '''job waiting to run'''
133
+ """job waiting to run"""
137
134
  return self.delay_timer.runtime < self.delay_time
138
135
 
139
136
  def renew(self, delay: Optional[TimeUnit] = None) -> None:
140
- '''renew delay time'''
137
+ """renew delay time"""
141
138
  if delay is not None:
142
139
  self.__delay_time = float(max(delay, self.MIN_DELAY_TIME))
143
140
  self.delay_timer.restart()
144
141
 
145
142
  def run(self) -> bool:
146
- '''run delay job'''
143
+ """run delay job"""
147
144
  self.delay_timer.alarm(self.delay_time)
148
145
  assert not self.waiting, f"{self} is waiting to run"
149
146
  return super().run()
150
147
 
151
148
 
152
149
  class DaemonTaskJob(TaskJob):
153
- '''Daemon Task Job'''
150
+ """Daemon Task Job"""
154
151
 
155
152
  def __init__(self, no: int, fn: Callable, *args: Any, **kwargs: Any):
156
153
  self.__counter: StatusCountMeter = StatusCountMeter()
@@ -163,43 +160,44 @@ class DaemonTaskJob(TaskJob):
163
160
 
164
161
  @property
165
162
  def daemon_counter(self) -> StatusCountMeter:
166
- '''daemon status counter'''
163
+ """daemon status counter"""
167
164
  return self.__counter
168
165
 
169
166
  @property
170
167
  def daemon_running(self) -> bool:
171
- '''daemon running flag'''
168
+ """daemon running flag"""
172
169
  return self.__running
173
170
 
174
171
  def run_in_background(self) -> Thread:
175
- '''run job in daemon mode in background'''
176
- thread: Thread = Thread(target=self.run)
172
+ """run job in daemon mode in background"""
173
+ thread: Thread = Thread(target=self.run, daemon=True)
177
174
  thread.start()
178
175
  return thread
179
176
 
180
177
  def run(self):
181
- '''run job in daemon mode in current thread'''
178
+ """run job in daemon mode in current thread"""
182
179
  self.__running = True
183
180
  while self.daemon_running:
184
181
  success: bool = super().run()
185
182
  self.daemon_counter.inc(success)
183
+ sleep(0.05 if success else 0.1)
186
184
 
187
185
  def shutdown(self) -> None:
188
- '''wait for job to finish'''
186
+ """wait for job to finish"""
189
187
  self.__running = False
190
188
  super().shutdown()
191
189
 
192
190
  def startup(self) -> None:
193
- '''same as run in background'''
191
+ """same as run in background"""
194
192
  self.run_in_background()
195
193
 
196
194
  def restart(self) -> None:
197
- '''restart job'''
195
+ """restart job"""
198
196
  self.shutdown()
199
197
  self.startup()
200
198
 
201
199
  def barrier(self) -> None:
202
- '''same as restart'''
200
+ """same as restart"""
203
201
  self.restart()
204
202
 
205
203
 
@@ -210,12 +208,11 @@ else: # Python3.8 TypeError
210
208
 
211
209
 
212
210
  class TaskPool(Dict[int, TaskJob]): # noqa: E501, pylint: disable=too-many-instance-attributes
213
- '''Task Thread Pool'''
211
+ """Task Thread Pool"""
214
212
 
215
213
  def __init__(self, workers: int = 1, jobs: int = 0, prefix: str = "task"):
216
214
  wsize: int = max(workers, 1)
217
215
  qsize = max(wsize, jobs) if jobs > 0 else jobs
218
- self.__cmds: Command = Command()
219
216
  self.__jobs: JobQueue = Queue(qsize)
220
217
  self.__prefix: str = prefix or "task"
221
218
  self.__status: StatusCountMeter = StatusCountMeter()
@@ -235,46 +232,37 @@ class TaskPool(Dict[int, TaskJob]): # noqa: E501, pylint: disable=too-many-inst
235
232
 
236
233
  @property
237
234
  def jobs(self) -> JobQueue:
238
- '''task jobs'''
235
+ """task jobs"""
239
236
  return self.__jobs
240
237
 
241
- @property
242
- def cmds(self) -> Command:
243
- '''command-line toolkit'''
244
- return self.__cmds
245
-
246
238
  @property
247
239
  def thread_name_prefix(self) -> str:
248
- '''task thread name prefix'''
240
+ """task thread name prefix"""
249
241
  return self.__prefix
250
242
 
251
243
  @property
252
244
  def threads(self) -> Set[Thread]:
253
- '''task threads'''
245
+ """task threads"""
254
246
  return self.__threads
255
247
 
256
248
  @property
257
249
  def running(self) -> bool:
258
- '''task threads are started'''
250
+ """task threads are started"""
259
251
  return self.__running
260
252
 
261
253
  @property
262
254
  def workers(self) -> int:
263
- '''task workers'''
255
+ """task workers"""
264
256
  return self.__workers
265
257
 
266
258
  @property
267
259
  def status_counter(self) -> StatusCountMeter:
268
- '''task job status counter'''
260
+ """task job status counter"""
269
261
  return self.__status
270
262
 
271
263
  def task(self):
272
- '''execute a task from jobs queue'''
264
+ """execute a task from jobs queue"""
273
265
  status_counter: StatusCountMeter = StatusCountMeter()
274
-
275
- logger: Logger = self.cmds.logger
276
- logger.debug("Task thread %s is running", current_thread().name)
277
-
278
266
  while True:
279
267
  job: Optional[TaskJob] = self.jobs.get(block=True)
280
268
  if job is None: # stop task
@@ -292,9 +280,6 @@ class TaskPool(Dict[int, TaskJob]): # noqa: E501, pylint: disable=too-many-inst
292
280
  self.status_counter.inc(True)
293
281
  status_counter.inc(True)
294
282
 
295
- logger.debug("Task thread %s is stopped, %s", current_thread().name,
296
- f"{status_counter.total} jobs: {status_counter.success} success and {status_counter.failure} failure") # noqa:E501
297
-
298
283
  def submit_job(self, job: TaskJob) -> TaskJob:
299
284
  assert isinstance(job, TaskJob), f"{job} is not a TaskJob"
300
285
  assert job.id not in self, f"{job} id is already in pool"
@@ -304,21 +289,20 @@ class TaskPool(Dict[int, TaskJob]): # noqa: E501, pylint: disable=too-many-inst
304
289
  return job
305
290
 
306
291
  def submit_task(self, fn: Callable, *args: Any, **kwargs: Any) -> TaskJob:
307
- '''submit a task to jobs queue'''
292
+ """submit a task to jobs queue"""
308
293
  with self.__intlock: # generate job id under lock protection
309
294
  sn: int = self.__counter.inc() # serial number
310
295
  return self.submit_job(TaskJob(sn, fn, *args, **kwargs))
311
296
 
312
297
  def submit_delay_task(self, delay: TimeUnit, fn: Callable, *args: Any, **kwargs: Any) -> TaskJob: # noqa:E501
313
- '''submit a delay task to jobs queue'''
298
+ """submit a delay task to jobs queue"""
314
299
  with self.__intlock: # generate job id under lock protection
315
300
  sn: int = self.__counter.inc() # serial number
316
301
  return self.submit_job(DelayTaskJob(delay, sn, fn, *args, **kwargs)) # noqa:E501
317
302
 
318
303
  def shutdown(self) -> None:
319
- '''stop all task threads and waiting for all jobs finish'''
304
+ """stop all task threads and waiting for all jobs finish"""
320
305
  with self.__intlock: # block submit new tasks
321
- self.cmds.logger.debug("Shutdown %s tasks", self.thread_name_prefix) # noqa:E501
322
306
  self.__running = False
323
307
  self.jobs.put(None) # notice tasks
324
308
  while len(self.threads) > 0:
@@ -330,21 +314,20 @@ class TaskPool(Dict[int, TaskJob]): # noqa: E501, pylint: disable=too-many-inst
330
314
  raise RuntimeError(f"Unexecuted job: {job}") # noqa:E501, pragma: no cover
331
315
 
332
316
  def startup(self) -> None:
333
- '''start task threads'''
317
+ """start task threads"""
334
318
  with self.__intlock:
335
- self.cmds.logger.debug("Startup %s tasks", self.thread_name_prefix)
336
319
  for i in range(self.workers):
337
320
  thread_name: str = f"{self.thread_name_prefix}_{i}"
338
- thread = Thread(name=thread_name, target=self.task)
321
+ thread = Thread(name=thread_name, target=self.task, daemon=True) # noqa:E501
339
322
  self.threads.add(thread)
340
323
  thread.start() # run
341
324
  self.__running = True
342
325
 
343
326
  def restart(self) -> None:
344
- '''stop submit new tasks and waiting for all submitted tasks to end'''
327
+ """stop submit new tasks and waiting for all submitted tasks to end"""
345
328
  self.shutdown()
346
329
  self.startup()
347
330
 
348
331
  def barrier(self) -> None:
349
- '''same as restart'''
332
+ """same as restart"""
350
333
  self.restart()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xkits-thread
3
- Version: 0.1
3
+ Version: 0.2
4
4
  Summary: Thread module
5
5
  Home-page: https://github.com/bondbox/xthreads/
6
6
  Author: Mingzhe Zou
@@ -16,8 +16,6 @@ Classifier: Programming Language :: Python :: 3
16
16
  Requires-Python: >=3.8
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: xkits-command>=0.2
20
- Requires-Dist: xkits-logger>=0.1
21
19
  Requires-Dist: xkits-lib>=0.1
22
20
 
23
21
  # xthreads
@@ -0,0 +1 @@
1
+ xkits-lib>=0.1
@@ -1,3 +0,0 @@
1
- xkits-command>=0.2
2
- xkits-logger>=0.1
3
- xkits-lib>=0.1
File without changes
File without changes
File without changes
File without changes