33"""
44# TODO: Rename the module to something that does not conflict with stdlib
55# concurrent
6+ import os
67import threading
78import atexit
89import logging
@@ -192,15 +193,53 @@ class ThreadExecutor(QObject, concurrent.futures.Executor):
192193
193194 threadPool : Optional[QThreadPool]
194195 Thread pool to be used by the instance of the Executor. If `None`
195- then ``QThreadPool.globalInstance()`` will be used.
196+ then a private global thread pool will be used.
196197
198+ .. versionchanged:: 3.15
199+ Before 3.15 a `QThreadPool.globalPool()` was used as the default.
200+
201+ .. warning::
202+ If you pass a custom `QThreadPool` make sure it creates threads
203+ with sufficient stack size for the tasks submitted to the executor
204+ (see `QThreadPool.setStackSize`).
197205 """
206+ # A default thread pool. Replaced QThreadPool due to insufficient default
207+ # stack size for created threads (QTBUG-2568). Not using even on
208+ # Qt >= 5.10 just for consistency sake.
209+ class __global :
210+ __lock = threading .Lock ()
211+ __instance = None
212+
213+ @classmethod
214+ def instance (cls ):
215+ # type: () -> concurrent.futures.ThreadPoolExecutor
216+ with cls .__lock :
217+ if cls .__instance is None :
218+ cls .__instance = concurrent .futures .ThreadPoolExecutor (
219+ max_workers = (os .cpu_count () or 1 )
220+ )
221+ return cls .__instance
198222
199223 def __init__ (self , parent = None , threadPool = None , ** kwargs ):
200224 super ().__init__ (parent , ** kwargs )
225+
201226 if threadPool is None :
202- threadPool = QThreadPool .globalInstance ()
227+ threadPool = self .__global .instance ()
228+
203229 self ._threadPool = threadPool
230+ if isinstance (threadPool , QThreadPool ):
231+ def start (runnable ):
232+ # type: (QRunnable) -> None
233+ threadPool .start (runnable )
234+ elif isinstance (threadPool , concurrent .futures .Executor ):
235+ # adapt to Executor interface
236+ def start (runnable ):
237+ # type: (QRunnable) -> None
238+ threadPool .submit (runnable .run )
239+ else :
240+ raise TypeError ("Invalid `threadPool` type '{}'"
241+ .format (type (threadPool ).__name__ ))
242+ self .__start = start
204243 self ._depot_thread = None
205244 self ._futures = []
206245 self ._shutdown = False
@@ -233,7 +272,7 @@ def submit(self, func, *args, **kwargs):
233272
234273 self ._futures .append (f )
235274 f .add_done_callback (self ._future_done )
236- self ._threadPool . start (runnable )
275+ self .__start (runnable )
237276 return f
238277
239278 def submit_task (self , task ):
@@ -249,7 +288,7 @@ def submit_task(self, task):
249288
250289 self ._futures .append (f )
251290 f .add_done_callback (self ._future_done )
252- self ._threadPool . start (runnable )
291+ self .__start (runnable )
253292 return f
254293
255294 def __make_task_runnable (self , task ):
0 commit comments