Concurrent Futures API#
lithops.concurrent.futures is a drop-in for Python’s
concurrent.futures
Executor interface. Swap the import and the same client keeps working:
# from concurrent.futures import ProcessPoolExecutor, as_completed, wait
from lithops.concurrent.futures import ProcessPoolExecutor, as_completed, wait
def same_client(executor):
with executor:
future = executor.submit(pow, 323, 1235)
print(future.result())
print(list(executor.map(abs, [-1, 2, -3])))
same_client(ProcessPoolExecutor())
ThreadPoolExecutor is provided under the same name for import compatibility;
both names run tasks on Lithops workers.
This is separate from the Core API (lithops.FunctionExecutor),
whose map() returns futures, which has call_async() instead of submit(),
and whose wait() is a method with Lithops-specific return_when values.
Implemented standard-library surface#
The module exports the names application code actually uses:
Executor —
submit(), eagermap()(results, not futures),shutdown(wait=True, *, cancel_futures=False), context managerProcessPoolExecutor / ThreadPoolExecutor — Lithops-backed pools
Future — subclass of
concurrent.futures.Future:result(),exception(),done(),running(),cancel(),cancelled(),add_done_callback()wait / as_completed — same contract and constants (
FIRST_COMPLETED,FIRST_EXCEPTION,ALL_COMPLETED)Exceptions —
CancelledError,TimeoutError,BrokenExecutor,InvalidStateError
InterpreterPoolExecutor (Python 3.14) is not implemented: Lithops has no
isolated-interpreter workers.
map() submits one Lithops map() job for the whole iterable, not one
submit() per item. Callables travel through a trampoline, so builtins such
as abs and pow work. Its chunksize is how many items each Lithops
worker takes, which is what it means for the standard ProcessPoolExecutor
too; left unset, the chunksize of the Lithops configuration applies rather
than the standard library default of one item per worker.
from lithops.concurrent.futures import FunctionExecutor, as_completed
def load(url):
return url, len(url)
with FunctionExecutor() as executor:
futures = {executor.submit(load, url): url for url in ('a', 'bb', 'ccc')}
for future in as_completed(futures):
url, size = future.result()
print(url, size)
Mode-specific subclasses LocalhostExecutor, ServerlessExecutor and
StandaloneExecutor pin the Lithops execution mode the same way the Core API
executors do. You can wrap an existing Core API executor:
import lithops
from lithops.concurrent.futures import FunctionExecutor
fexec = lithops.FunctionExecutor()
with FunctionExecutor(executor=fexec) as executor:
print(executor.submit(pow, 2, 8).result())
Runtime differences#
The API matches concurrent.futures. The runtime is Lithops:
Workers are Lithops activations, not local threads or
multiprocessingprocesses.mp_context,max_tasks_per_child, andthread_name_prefixare ignored.initializer/initargsare not supported (workers are ephemeral) and raiseNotImplementedErrorif provided.cancel()cannot stop a job Lithops has already dispatched.submit()marks the future as running immediately, socancel()returnsFalse, andshutdown(cancel_futures=True)therefore still waits the calls out.Lithops job options (
runtime_memory,extra_env,execution_timeout,include_modules,exclude_modules) are set on the executor. Keyword arguments tosubmit(fn, *args, **kwargs)are passed tofn.Each
Futurealso exposeslithops_futureandstats.A call Lithops loses track of raises
RuntimeErrorrather than handing back a silentNone. It fails that one future; the executor stays usable.RetryingFunctionExecutorcannot be wrapped. Its retries are driven from its ownwait(), which this adapter never calls, so wrapping it would quietly give you no retries at all. Wrap theFunctionExecutorit holds.
Completion is tracked by the Lithops job monitor, the same one the native
wait() uses: one batched poll per round for the whole job rather than one
status read per call. Results are downloaded off the tracking thread, so a
slow object does not hold up the futures behind it, and done() never
blocks on storage.
concurrent.futures-compatible executors backed by Lithops.
The native Lithops executors (lithops.FunctionExecutor and friends)
are intentionally different from concurrent.futures: map() returns
futures, there is no submit(), and wait() lives on the executor.
This module is the drop-in interface for code that already talks to
ThreadPoolExecutor / ProcessPoolExecutor:
from lithops.concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as executor:
future = executor.submit(pow, 2, 8)
print(future.result())
print(list(executor.map(abs, [-1, 2, -3])))
Future subclasses concurrent.futures.Future, so the standard
library’s wait() and as_completed() work unchanged, including
with futures from other executors.
- class lithops.concurrent.futures.FunctionExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
Executorconcurrent.futures.Executor that runs callables on Lithops workers.
submit(fn, *args, **kwargs)andmap(fn, *iterables)follow the standard library:mapis eager and yields results, not futures. Internally,mapis a single Lithopsmap()job rather than onesubmitper item, so a large iterator still benefits from Lithops batching.- Parameters:
max_workers – Passed through to the Lithops compute backend
executor – An existing
lithops.FunctionExecutor(or compatible object) to wrap. When omitted, one is created from**kwargsinitializer – Not supported; Lithops workers are ephemeral. Providing a callable raises
NotImplementedErrorinitargs – Ignored unless
initializeris setruntime_memory – Memory (MB) for every submitted call
extra_env – Extra environment variables for every submitted call
execution_timeout – Max seconds each function activation may run
include_modules – Modules to pickle into the worker payload
exclude_modules – Modules to keep out of the worker payload
kwargs – Forwarded to the Lithops executor constructor (
config,backend,storage,log_level, …)
- property lithops_executor#
The wrapped Lithops FunctionExecutor.
- map(fn, *iterables, timeout=None, chunksize=None, buffersize=None)#
Eager map, as in the standard library: it returns an iterator over the results, and every call is submitted before it does.
chunksizeis how many items each Lithops worker takes, which is what it means for the standardProcessPoolExecutortoo. Left unset, the Lithops configuration decides, rather than the standard library default of one item per worker overriding it
- shutdown(wait=True, *, cancel_futures=False)#
Clean-up the resources associated with the Executor.
It is safe to call this method several times. Otherwise, no other methods can be called after this one.
- Args:
- wait: If True then shutdown will not return until all running
futures have finished executing and the resources used by the executor have been reclaimed.
- cancel_futures: If True then shutdown will cancel all pending
futures. Futures that are completed or running will not be cancelled.
- submit(fn, /, *args, **kwargs)#
Schedules
fn(*args, **kwargs)to run on a Lithops worker.- Parameters:
fn – The callable to run
args – Positional arguments for
fnkwargs – Keyword arguments for
fn
- Returns:
A
Futurerepresenting the call- Raises:
RuntimeError – If the executor has been shut down
concurrent.futures.BrokenExecutor – If the executor stopped working and can no longer run calls
- class lithops.concurrent.futures.Future(lithops_future=None, adapter=None)#
Bases:
FutureA concurrent.futures.Future backed by a Lithops ResponseFuture.
Created by
FunctionExecutor.submit(). The underlying Lithops future is available aslithops_futurefor stats and other Lithops-specific attributes.- done()#
Return True if the future was cancelled or finished executing.
- exception(timeout=None)#
Returns the exception raised by the call, waiting for it to finish.
- Parameters:
timeout – Seconds to wait if the call is not done yet.
Nonewaits without limit- Returns:
The exception raised by the call, or
Noneif it returned normally- Raises:
concurrent.futures.CancelledError – If the future was cancelled
TimeoutError – If the call did not finish within
timeout
- property lithops_future#
The Lithops ResponseFuture this object is tracking.
- result(timeout=None)#
Returns the result of the call, waiting for it to finish.
- Parameters:
timeout – Seconds to wait if the call is not done yet.
Nonewaits without limit- Returns:
The value returned by the call
- Raises:
concurrent.futures.CancelledError – If the future was cancelled
TimeoutError – If the call did not finish within
timeoutException – The exception raised by the call, if it raised one
- property stats#
Execution stats from the Lithops future, once they are available.
- class lithops.concurrent.futures.LocalhostExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
FunctionExecutorFunctionExecutor pinned to the Lithops localhost backend.
- class lithops.concurrent.futures.ProcessPoolExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
FunctionExecutorDrop-in replacement for
concurrent.futures.ProcessPoolExecutor.Tasks run on Lithops workers (localhost, serverless, or standalone) instead of a local
multiprocessingpool. Constructor arguments that only apply to the standard library (mp_context,max_tasks_per_child) are ignored.
- class lithops.concurrent.futures.ServerlessExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
FunctionExecutorFunctionExecutor pinned to a Lithops serverless backend.
- class lithops.concurrent.futures.StandaloneExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
FunctionExecutorFunctionExecutor pinned to a Lithops standalone backend.
- class lithops.concurrent.futures.ThreadPoolExecutor(max_workers=None, *, executor=None, initializer=None, initargs=(), runtime_memory=None, extra_env=None, execution_timeout=None, include_modules=None, exclude_modules=None, **kwargs)#
Bases:
FunctionExecutorDrop-in replacement for
concurrent.futures.ThreadPoolExecutor.Tasks still run on Lithops workers, not in local threads. Use this name when swapping
from concurrent.futures import ThreadPoolExecutor.thread_name_prefixis ignored.
- lithops.concurrent.futures.as_completed(fs, timeout=None)#
Yield futures as they complete. Same contract as concurrent.futures.as_completed.
- lithops.concurrent.futures.wait(fs, timeout=None, return_when='ALL_COMPLETED')#
Wait for futures to complete. Same contract as concurrent.futures.wait.