55import inspect
66import itertools
77import pickle
8+ import platform
89import time
910import traceback
1011import warnings
1112from contextlib import suppress
1213
14+ import loky
15+
1316from adaptive .notebook_integration import in_ipynb , live_info , live_plot
1417
1518try :
3336except ModuleNotFoundError :
3437 with_mpi4py = False
3538
36- try :
37- import loky
38-
39- with_loky = True
40- except ModuleNotFoundError :
41- with_loky = False
4239
4340with suppress (ModuleNotFoundError ):
4441 import uvloop
4542
4643 asyncio .set_event_loop_policy (uvloop .EventLoopPolicy ())
4744
4845
49- _default_executor = (
50- loky .get_reusable_executor if with_loky else concurrent .ProcessPoolExecutor
51- )
46+ if platform .system () == "Linux" :
47+ _default_executor = concurrent .ProcessPoolExecutor
48+ else :
49+ # On Windows and MacOS functions, the __main__ module must be
50+ # importable by worker subprocesses. This means that
51+ # ProcessPoolExecutor will not work in the interactive interpreter.
52+ # On Linux the whole process is forked, so the issue does not appear.
53+ # See https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor
54+ # and https://github.com/python-adaptive/adaptive/issues/301
55+ _default_executor = loky .get_reusable_executor
5256
5357
5458class BaseRunner (metaclass = abc .ABCMeta ):
@@ -65,7 +69,8 @@ class BaseRunner(metaclass=abc.ABCMeta):
6569 `mpi4py.futures.MPIPoolExecutor`, `ipyparallel.Client` or\
6670 `loky.get_reusable_executor`, optional
6771 The executor in which to evaluate the function to be learned.
68- If not provided, a new `~concurrent.futures.ProcessPoolExecutor`.
72+ If not provided, a new `~concurrent.futures.ProcessPoolExecutor` on
73+ Linux, and a `loky.get_reusable_executor` on MacOS and Windows.
6974 ntasks : int, optional
7075 The number of concurrent function evaluations. Defaults to the number
7176 of cores available in `executor`.
@@ -317,7 +322,8 @@ class BlockingRunner(BaseRunner):
317322 `mpi4py.futures.MPIPoolExecutor`, `ipyparallel.Client` or\
318323 `loky.get_reusable_executor`, optional
319324 The executor in which to evaluate the function to be learned.
320- If not provided, a new `~concurrent.futures.ProcessPoolExecutor`.
325+ If not provided, a new `~concurrent.futures.ProcessPoolExecutor` on
326+ Linux, and a `loky.get_reusable_executor` on MacOS and Windows.
321327 ntasks : int, optional
322328 The number of concurrent function evaluations. Defaults to the number
323329 of cores available in `executor`.
@@ -433,7 +439,8 @@ class AsyncRunner(BaseRunner):
433439 `mpi4py.futures.MPIPoolExecutor`, `ipyparallel.Client` or\
434440 `loky.get_reusable_executor`, optional
435441 The executor in which to evaluate the function to be learned.
436- If not provided, a new `~concurrent.futures.ProcessPoolExecutor`.
442+ If not provided, a new `~concurrent.futures.ProcessPoolExecutor` on
443+ Linux, and a `loky.get_reusable_executor` on MacOS and Windows.
437444 ntasks : int, optional
438445 The number of concurrent function evaluations. Defaults to the number
439446 of cores available in `executor`.
@@ -814,7 +821,7 @@ def _get_ncores(ex):
814821 ex , (concurrent .ProcessPoolExecutor , concurrent .ThreadPoolExecutor )
815822 ):
816823 return ex ._max_workers # not public API!
817- elif with_loky and isinstance (ex , loky .reusable_executor ._ReusablePoolExecutor ):
824+ elif isinstance (ex , loky .reusable_executor ._ReusablePoolExecutor ):
818825 return ex ._max_workers # not public API!
819826 elif isinstance (ex , SequentialExecutor ):
820827 return 1
0 commit comments