summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott <[email protected]>2022-01-24 14:51:17 -0800
committerScott <[email protected]>2022-01-24 14:51:17 -0800
commit22be1f3055cb905aa0b371779e6ab3098f57e4a2 (patch)
tree04faf2bb9b000f2cc76af9d6a68a02212ebc160a
parent67e324d8995c18445574415eb44abcfdce436bdc (diff)
Make parallelize remember to shutdown the default executors atexit.
-rw-r--r--parallelize.py35
1 files changed, 19 insertions, 16 deletions
diff --git a/parallelize.py b/parallelize.py
index d9c202f..698a7ec 100644
--- a/parallelize.py
+++ b/parallelize.py
@@ -2,6 +2,7 @@
"""A decorator to help with dead simple parallelization."""
+import atexit
from enum import Enum
import functools
import typing
@@ -14,23 +15,21 @@ class Method(Enum):
def parallelize(
- _funct: typing.Optional[typing.Callable] = None,
- *,
- method: Method = Method.THREAD
+ _funct: typing.Optional[typing.Callable] = None, *, method: Method = Method.THREAD
) -> typing.Callable:
"""Usage:
- @parallelize # defaults to thread-mode
- def my_function(a, b, c) -> int:
- ...do some slow / expensive work, e.g., an http request
+ @parallelize # defaults to thread-mode
+ def my_function(a, b, c) -> int:
+ ...do some slow / expensive work, e.g., an http request
- @parallelize(method=Method.PROCESS)
- def my_other_function(d, e, f) -> str:
- ...do more really expensice work, e.g., a network read
+ @parallelize(method=Method.PROCESS)
+ def my_other_function(d, e, f) -> str:
+ ...do more really expensice work, e.g., a network read
- @parallelize(method=Method.REMOTE)
- def my_other_other_function(g, h) -> int:
- ...this work will be distributed to a remote machine pool
+ @parallelize(method=Method.REMOTE)
+ def my_other_other_function(g, h) -> int:
+ ...this work will be distributed to a remote machine pool
This decorator will invoke the wrapped function on:
@@ -52,9 +51,14 @@ def parallelize(
your machine with processes or your network with remote processes
beyond the control mechanisms built into one instance of the pool.
Be careful.
+
+ Also note: there is a non trivial overhead of pickling code and
+ scp'ing it over the network when you use Method.REMOTE. There's
+ a smaller but still considerable cost of creating a new process
+ and passing code to/from it when you use Method.PROCESS.
"""
- def wrapper(funct: typing.Callable):
+ def wrapper(funct: typing.Callable):
@functools.wraps(funct)
def inner_wrapper(*args, **kwargs):
import executors
@@ -67,9 +71,7 @@ def parallelize(
newargs.append(smart_future.SmartFuture.resolve(arg))
newkwargs = {}
for kw in kwargs:
- newkwargs[kw] = smart_future.SmartFuture.resolve(
- kwargs[kw]
- )
+ newkwargs[kw] = smart_future.SmartFuture.resolve(kwargs[kw])
executor = None
if method == Method.PROCESS:
@@ -79,6 +81,7 @@ def parallelize(
elif method == Method.REMOTE:
executor = executors.DefaultExecutors().remote_pool()
assert executor is not None
+ atexit.register(executors.DefaultExecutors().shutdown)
future = executor.submit(funct, *newargs, **newkwargs)