Skip to content

Commit 15a81c7

Browse files
authored
Do not implicitly shut down the shared reusable executor (#498)
All runners with executor=None now share loky's reusable executor singleton, so a finishing (or cancelled) runner must not shut it down: another runner may still be submitting work to it, which raised loky.process_executor.ShutdownExecutorError (seen in the Read the Docs build of tutorial.advanced-topics.md). The executor is only shut down when the user explicitly passes shutdown_executor=True; idle loky workers time out on their own.
1 parent 1bb8618 commit 15a81c7

1 file changed

Lines changed: 14 additions & 9 deletions

File tree

adaptive/runner.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ class BaseRunner(metaclass=abc.ABCMeta):
9292
If True, record the method calls made to the learner by this runner.
9393
shutdown_executor : bool, default: False
9494
If True, shutdown the executor when the runner has completed. If
95-
`executor` is not provided then the executor created internally
96-
by the runner is shut down, regardless of this parameter.
95+
`executor` is not provided then the runner uses loky's reusable
96+
executor, which is shared between runners and is therefore not
97+
shut down unless this parameter is True.
9798
retries : int, default: 0
9899
Maximum amount of retries of a certain point ``x`` in
99100
``learner.function(x)``. After `retries` is reached for ``x``
@@ -159,9 +160,11 @@ def __init__(
159160

160161
self._pending_tasks: dict[FutureTypes, int] = {}
161162

162-
# if we instantiate our own executor, then we are also responsible
163-
# for calling 'shutdown'
164-
self.shutdown_executor = shutdown_executor or (executor is None)
163+
# The internally created executor (when `executor is None`) is loky's
164+
# reusable executor, a singleton shared between all runners, so we
165+
# must not shut it down implicitly: another runner may still be using
166+
# it. Pass `shutdown_executor=True` to shut it down anyway.
167+
self.shutdown_executor = shutdown_executor
165168

166169
self.learner = learner
167170
self.log: list | None = [] if log else None
@@ -378,8 +381,9 @@ class BlockingRunner(BaseRunner):
378381
If True, record the method calls made to the learner by this runner.
379382
shutdown_executor : bool, default: False
380383
If True, shutdown the executor when the runner has completed. If
381-
`executor` is not provided then the executor created internally
382-
by the runner is shut down, regardless of this parameter.
384+
`executor` is not provided then the runner uses loky's reusable
385+
executor, which is shared between runners and is therefore not
386+
shut down unless this parameter is True.
383387
retries : int, default: 0
384388
Maximum amount of retries of a certain point ``x`` in
385389
``learner.function(x)``. After `retries` is reached for ``x``
@@ -524,8 +528,9 @@ class AsyncRunner(BaseRunner):
524528
If True, record the method calls made to the learner by this runner.
525529
shutdown_executor : bool, default: False
526530
If True, shutdown the executor when the runner has completed. If
527-
`executor` is not provided then the executor created internally
528-
by the runner is shut down, regardless of this parameter.
531+
`executor` is not provided then the runner uses loky's reusable
532+
executor, which is shared between runners and is therefore not
533+
shut down unless this parameter is True.
529534
ioloop : ``asyncio.AbstractEventLoop``, optional
530535
The ioloop in which to run the learning algorithm. If not provided,
531536
the default event loop is used.

0 commit comments

Comments
 (0)