43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
|
from concurrent.futures import ThreadPoolExecutor
|
||
|
from functools import partial
|
||
|
|
||
|
from trollius import get_event_loop, coroutine
|
||
|
|
||
|
|
||
|
def wrap_with_threadpool(obj, worker_threads=1):
|
||
|
"""
|
||
|
Wraps a class in an async executor so that it can be safely used in an event loop like trollius.
|
||
|
"""
|
||
|
async_executor = ThreadPoolExecutor(worker_threads)
|
||
|
return AsyncWrapper(obj, executor=async_executor), async_executor
|
||
|
|
||
|
|
||
|
class AsyncWrapper(object):
|
||
|
""" Wrapper class which will transform a syncronous library to one that can be used with
|
||
|
trollius coroutines.
|
||
|
"""
|
||
|
def __init__(self, delegate, loop=None, executor=None):
|
||
|
self._loop = loop if loop is not None else get_event_loop()
|
||
|
self._delegate = delegate
|
||
|
self._executor = executor
|
||
|
|
||
|
def __getattr__(self, attrib):
|
||
|
delegate_attr = getattr(self._delegate, attrib)
|
||
|
|
||
|
if not callable(delegate_attr):
|
||
|
return delegate_attr
|
||
|
|
||
|
def wrapper(*args, **kwargs):
|
||
|
""" Wraps the delegate_attr with primitives that will transform sync calls to ones shelled
|
||
|
out to a thread pool.
|
||
|
"""
|
||
|
callable_delegate_attr = partial(delegate_attr, *args, **kwargs)
|
||
|
return self._loop.run_in_executor(self._executor, callable_delegate_attr)
|
||
|
|
||
|
return wrapper
|
||
|
|
||
|
@coroutine
|
||
|
def __call__(self, *args, **kwargs):
|
||
|
callable_delegate_attr = partial(self._delegate, *args, **kwargs)
|
||
|
return self._loop.run_in_executor(self._executor, callable_delegate_attr)
|