20
20
21
21
import logging
22
22
from functools import wraps
23
- from threading import Thread , BoundedSemaphore , Lock , Event , current_thread
23
+ from threading import Thread , Lock , Event , current_thread
24
24
from time import sleep
25
+ from queue import Queue , Empty
25
26
26
- from queue import Empty
27
+ from future . builtins import range
27
28
28
29
from telegram import (TelegramError , NullHandler )
30
+ from telegram .utils import request
29
31
from telegram .ext .handler import Handler
30
32
from telegram .utils .deprecate import deprecate
31
33
32
34
logging .getLogger (__name__ ).addHandler (NullHandler ())
33
35
34
- semaphore = None
35
- async_threads = set ()
36
+ ASYNC_QUEUE = Queue ()
37
+ ASYNC_THREADS = set ()
36
38
""":type: set[Thread]"""
37
- async_lock = Lock ()
39
+ ASYNC_LOCK = Lock () # guards ASYNC_THREADS
38
40
DEFAULT_GROUP = 0
39
41
40
42
43
+ def _pooled ():
44
+ """
45
+ A wrapper to run a thread in a thread pool
46
+ """
47
+ while 1 :
48
+ try :
49
+ func , args , kwargs = ASYNC_QUEUE .get ()
50
+
51
+ # If unpacking fails, the thread pool is being closed from Updater._join_async_threads
52
+ except TypeError :
53
+ logging .getLogger (__name__ ).debug ("Closing run_async thread %s/%d" %
54
+ (current_thread ().getName (), len (ASYNC_THREADS )))
55
+ break
56
+
57
+ try :
58
+ func (* args , ** kwargs )
59
+
60
+ except :
61
+ logging .getLogger (__name__ ).exception ("run_async function raised exception" )
62
+
63
+
41
64
def run_async (func ):
42
65
"""
43
66
Function decorator that will run the function in a new thread.
@@ -53,30 +76,11 @@ def run_async(func):
53
76
# set a threading.Event to notify caller thread
54
77
55
78
@wraps (func )
56
- def pooled (* pargs , ** kwargs ):
57
- """
58
- A wrapper to run a thread in a thread pool
59
- """
60
- try :
61
- result = func (* pargs , ** kwargs )
62
- finally :
63
- semaphore .release ()
64
-
65
- with async_lock :
66
- async_threads .remove (current_thread ())
67
- return result
68
-
69
- @wraps (func )
70
- def async_func (* pargs , ** kwargs ):
79
+ def async_func (* args , ** kwargs ):
71
80
"""
72
81
A wrapper to run a function in a thread
73
82
"""
74
- thread = Thread (target = pooled , args = pargs , kwargs = kwargs )
75
- semaphore .acquire ()
76
- with async_lock :
77
- async_threads .add (thread )
78
- thread .start ()
79
- return thread
83
+ ASYNC_QUEUE .put ((func , args , kwargs ))
80
84
81
85
return async_func
82
86
@@ -112,11 +116,18 @@ def __init__(self, bot, update_queue, workers=4, exception_event=None, job_queue
112
116
self .__stop_event = Event ()
113
117
self .__exception_event = exception_event or Event ()
114
118
115
- global semaphore
116
- if not semaphore :
117
- semaphore = BoundedSemaphore (value = workers )
118
- else :
119
- self .logger .debug ('Semaphore already initialized, skipping.' )
119
+ with ASYNC_LOCK :
120
+ if not ASYNC_THREADS :
121
+ if request .is_con_pool_initialized ():
122
+ raise RuntimeError ('Connection Pool already initialized' )
123
+
124
+ request .CON_POOL_SIZE = workers + 3
125
+ for i in range (workers ):
126
+ thread = Thread (target = _pooled , name = str (i ))
127
+ ASYNC_THREADS .add (thread )
128
+ thread .start ()
129
+ else :
130
+ self .logger .debug ('Thread pool already initialized, skipping.' )
120
131
121
132
def start (self ):
122
133
"""
@@ -136,7 +147,7 @@ def start(self):
136
147
self .running = True
137
148
self .logger .debug ('Dispatcher started' )
138
149
139
- while True :
150
+ while 1 :
140
151
try :
141
152
# Pop update from update queue.
142
153
update = self .update_queue .get (True , 1 )
@@ -150,7 +161,7 @@ def start(self):
150
161
continue
151
162
152
163
self .logger .debug ('Processing Update: %s' % update )
153
- self .processUpdate (update )
164
+ self .process_update (update )
154
165
155
166
self .running = False
156
167
self .logger .debug ('Dispatcher thread stopped' )
@@ -165,7 +176,7 @@ def stop(self):
165
176
sleep (0.1 )
166
177
self .__stop_event .clear ()
167
178
168
- def processUpdate (self , update ):
179
+ def process_update (self , update ):
169
180
"""
170
181
Processes a single update.
171
182
@@ -175,7 +186,7 @@ def processUpdate(self, update):
175
186
176
187
# An error happened while polling
177
188
if isinstance (update , TelegramError ):
178
- self .dispatchError (None , update )
189
+ self .dispatch_error (None , update )
179
190
180
191
else :
181
192
for group in self .groups :
@@ -190,7 +201,7 @@ def processUpdate(self, update):
190
201
'Update.' )
191
202
192
203
try :
193
- self .dispatchError (update , te )
204
+ self .dispatch_error (update , te )
194
205
except Exception :
195
206
self .logger .exception ('An uncaught error was raised while '
196
207
'handling the error' )
@@ -276,7 +287,7 @@ def remove_error_handler(self, callback):
276
287
if callback in self .error_handlers :
277
288
self .error_handlers .remove (callback )
278
289
279
- def dispatchError (self , update , error ):
290
+ def dispatch_error (self , update , error ):
280
291
"""
281
292
Dispatches an error.
282
293
0 commit comments