-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1323 from quantopian/pmap-blaze-query
ENH: Adds the ability to run blaze queries concurrently
- Loading branch information
Showing
3 changed files
with
195 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
from six.moves import map as imap | ||
from toolz import compose, identity | ||
|
||
|
||
class ApplyAsyncResult(object): | ||
"""An object that boxes results for calls to | ||
:meth:`~zipline.utils.pool.SequentialPool.apply_async`. | ||
Parameters | ||
---------- | ||
value : any | ||
The result of calling the function, or any exception that was raised. | ||
successful : bool | ||
If ``True``, ``value`` is the return value of the function. | ||
If ``False``, ``value`` is the exception that was raised when calling | ||
the functions. | ||
""" | ||
def __init__(self, value, successful): | ||
self._value = value | ||
self._successful = successful | ||
|
||
def successful(self): | ||
"""Did the function execute without raising an exception? | ||
""" | ||
return self._successful | ||
|
||
def get(self): | ||
"""Return the result of calling the function or reraise any exceptions | ||
that were raised. | ||
""" | ||
if not self._successful: | ||
raise self._value | ||
return self._value | ||
|
||
def ready(self): | ||
"""Has the function finished executing. | ||
Notes | ||
----- | ||
In the :class:`~zipline.utils.pool.SequentialPool` case, this is always | ||
``True``. | ||
""" | ||
return True | ||
|
||
def wait(self): | ||
"""Wait until the function is finished executing. | ||
Notes | ||
----- | ||
In the :class:`~zipline.utils.pool.SequentialPool` case, this is a nop | ||
because the function is computed eagerly in the same thread as the | ||
call to :meth:`~zipline.utils.pool.SequentialPool.apply_async`. | ||
""" | ||
pass | ||
|
||
|
||
class SequentialPool(object): | ||
"""A dummy pool object that iterates sequentially in a single thread. | ||
Methods | ||
------- | ||
map(f: callable[A, B], iterable: iterable[A]) -> list[B] | ||
Apply a function to each of the elements of ``iterable``. | ||
imap(f: callable[A, B], iterable: iterable[A]) -> iterable[B] | ||
Lazily apply a function to each of the elements of ``iterable``. | ||
imap_unordered(f: callable[A, B], iterable: iterable[A]) -> iterable[B] | ||
Lazily apply a function to each of the elements of ``iterable`` but | ||
yield values as they become available. The resulting iterable is | ||
unordered. | ||
Notes | ||
----- | ||
This object is useful for testing to mock out the ``Pool`` interface | ||
provided by gevent or multiprocessing. | ||
See Also | ||
-------- | ||
:class:`multiprocessing.Pool` | ||
""" | ||
map = staticmethod(compose(list, imap)) | ||
imap = imap_unordered = staticmethod(imap) | ||
|
||
@staticmethod | ||
def apply_async(f, args=(), kwargs=None, callback=None): | ||
"""Apply a function but emulate the API of an asynchronous call. | ||
Parameters | ||
---------- | ||
f : callable | ||
The function to call. | ||
args : tuple, optional | ||
The positional arguments. | ||
kwargs : dict, optional | ||
The keyword arguments. | ||
Returns | ||
------- | ||
future : ApplyAsyncResult | ||
The result of calling the function boxed in a future-like api. | ||
Notes | ||
----- | ||
This calls the function eagerly but wraps it so that ``SequentialPool`` | ||
can be used where a :class:`multiprocessing.Pool` or | ||
:class:`gevent.pool.Pool` would be used. | ||
""" | ||
try: | ||
value = (identity if callback is None else callback)( | ||
f(*args, **kwargs or {}), | ||
) | ||
successful = True | ||
except Exception as e: | ||
value = e | ||
successful = False | ||
|
||
return ApplyAsyncResult(value, successful) | ||
|
||
@staticmethod | ||
def apply(f, args=(), kwargs=None): | ||
"""Apply a function. | ||
Parameters | ||
---------- | ||
f : callable | ||
The function to call. | ||
args : tuple, optional | ||
The positional arguments. | ||
kwargs : dict, optional | ||
The keyword arguments. | ||
Returns | ||
------- | ||
result : any | ||
f(*args, **kwargs) | ||
""" | ||
return f(*args, **kwargs or {}) |