Pools from concurrent.futures
package are eager (which you of course want and which means they pick up calculations as soon as possible - some time between pool.submit()
call and associated future.result()
method returns).
From perspective of synchronous code you have two choices - either calculate tasks result on pool.submit()
call, or future.result()
retrieval.
I find second approach more natural since it better imitates "nonblocking" nature of pool.map()
from perspective of main thread - results can be obtained one after another as soon as they done calculating (rather then when they are all ready).
Here is my code (additional implementation of DummyFuture
is needed):
from concurrent.futures import Executor
from threading import Lock
from functools import partial
class DummyFuture():
def __init__(self, calculation) -> None:
self.calculation = calculation
def result(self, timeout=None):
return self.calculation()
def cancel(self):
pass
class DummyExecutor(Executor):
def __init__(self):
self._shutdown = False
self._shutdown_lock = Lock()
def submit(self, fn, /, *args, **kwargs):
with self._shutdown_lock:
if self._shutdown:
raise RuntimeError('cannot schedule new futures after shutdown')
return DummyFuture(partial(fn, *args, **kwargs))
def shutdown(self, wait=True, *, cancel_futures=False):
with self._shutdown_lock:
self._shutdown = True
(I have to give credit to mata's answer since it was initial start of my implementation.)
Executor
which on submit directly calls the callable and returns aFuture
object. A look a theThreadPoolExecutor
might help – Sallie