+ :class:`pyutils.parallelize.executors.RemoteExecutor` how to
+ invoke the :file:`remote_worker.py` on remote machines by
+ passing its path on remote worker machines in your setup via
+ the `--remote_worker_helper_path` commandline flag (or,
+ honestly, if you made it this far, just update the default in
+ this code -- find `executors.py` under `site-packages` in your
+ virtual environment and update the default value of the
+ `--remote_worker_helper_path` flag)
+
+ If you're trying to set this up and struggling, email me at
+
+ What you get back when you call a decorated function (using
+ threads, processes or a remote worker) is a
+ :class:`pyutils.parallelize.smart_future.SmartFuture`. This class
+ attempts to transparently wrap a normal Python :class:`Future`
+ (see
+ https://docs.python.org/3/library/concurrent.futures.html#future-objects).
+ If your code just uses the result of a `parallelized` method it
+ will block waiting on the result of the wrapped function as soon
+ as it uses that result in a manner that requires its value to be
+ known (e.g. using it in an expression, calling a method on it,
+ passing it into a method, hashing it / using it as a dict key,
+ etc...) But you can do operations that do not require the value
+ to be known (e.g. storing it in a list, storing it as a value in a
+ dict, etc...) safely without blocking.
+
+ There are two helper methods in
+ :mod:`pyutils.parallelize.smart_future` to help deal with these
+ :class:`SmartFuture` objects called
+ :meth:`pyutils.parallelize.smart_future.wait_all` and
+ :meth:`pyutils.parallelize.smart_future.wait_any`. These, when
+ given a collection of :class:`SmartFuture` objects,
+ will block until one (any) or all (all) are finished and yield the
+ finished objects to the caller. Callers can be confident that any
+ objects returned from these methods will not block when accessed.
+ See documentation in :mod:`pyutils.parallelize.smart_future` for
+ more details.