|
|
|
@ -15,13 +15,14 @@ |
|
|
|
|
|
|
|
|
|
cdef bint _grpc_aio_initialized = False |
|
|
|
|
# NOTE(lidiz) Theoretically, applications can run in multiple event loops as |
|
|
|
|
# long as they are in the same thread with same magic. However, I don't think |
|
|
|
|
# we should support this use case. So, the gRPC Python Async Stack should use |
|
|
|
|
# a single event loop picked by "init_grpc_aio". |
|
|
|
|
cdef object _grpc_aio_loop |
|
|
|
|
cdef object _event_loop_thread_ident |
|
|
|
|
# long as they are in the same thread with same magic. This is not a supported |
|
|
|
|
# use case. So, the gRPC Python Async Stack should use a single event loop |
|
|
|
|
# picked by "init_grpc_aio". |
|
|
|
|
cdef object _grpc_aio_loop # asyncio.AbstractEventLoop |
|
|
|
|
cdef int64_t _event_loop_thread_ident |
|
|
|
|
cdef str _GRPC_ASYNCIO_ENGINE = os.environ.get('GRPC_ASYNCIO_ENGINE', 'default').lower() |
|
|
|
|
grpc_aio_engine = None |
|
|
|
|
cdef object _grpc_initialization_lock = threading.Lock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AsyncIOEngine(enum.Enum): |
|
|
|
@ -36,51 +37,50 @@ def init_grpc_aio(): |
|
|
|
|
global _event_loop_thread_ident |
|
|
|
|
global grpc_aio_engine |
|
|
|
|
|
|
|
|
|
# Marks this function as called |
|
|
|
|
if _grpc_aio_initialized: |
|
|
|
|
return |
|
|
|
|
else: |
|
|
|
|
_grpc_aio_initialized = True |
|
|
|
|
|
|
|
|
|
# Picks the engine for gRPC AsyncIO Stack |
|
|
|
|
for engine_type in AsyncIOEngine: |
|
|
|
|
if engine_type.value == _GRPC_ASYNCIO_ENGINE: |
|
|
|
|
grpc_aio_engine = engine_type |
|
|
|
|
break |
|
|
|
|
if grpc_aio_engine is None or grpc_aio_engine is AsyncIOEngine.DEFAULT: |
|
|
|
|
grpc_aio_engine = AsyncIOEngine.CUSTOM_IO_MANAGER |
|
|
|
|
|
|
|
|
|
# Anchors the event loop that the gRPC library going to use. |
|
|
|
|
_grpc_aio_loop = asyncio.get_event_loop() |
|
|
|
|
_event_loop_thread_ident = threading.current_thread().ident |
|
|
|
|
|
|
|
|
|
if grpc_aio_engine is AsyncIOEngine.CUSTOM_IO_MANAGER: |
|
|
|
|
# Activates asyncio IO manager. |
|
|
|
|
# NOTE(lidiz) Custom IO manager must be activated before the first |
|
|
|
|
# `grpc_init()`. Otherwise, some special configurations in Core won't |
|
|
|
|
# pick up the change, and resulted in SEGFAULT or ABORT. |
|
|
|
|
install_asyncio_iomgr() |
|
|
|
|
|
|
|
|
|
# TODO(https://github.com/grpc/grpc/issues/22244) we need a the |
|
|
|
|
# grpc_shutdown_blocking() counterpart for this call. Otherwise, the gRPC |
|
|
|
|
# library won't shutdown cleanly. |
|
|
|
|
grpc_init() |
|
|
|
|
|
|
|
|
|
# Timers are triggered by the Asyncio loop. We disable |
|
|
|
|
# the background thread that is being used by the native |
|
|
|
|
# gRPC iomgr. |
|
|
|
|
grpc_timer_manager_set_threading(False) |
|
|
|
|
|
|
|
|
|
# gRPC callbaks are executed within the same thread used by the Asyncio |
|
|
|
|
# event loop, as it is being done by the other Asyncio callbacks. |
|
|
|
|
Executor.SetThreadingAll(False) |
|
|
|
|
else: |
|
|
|
|
# TODO(https://github.com/grpc/grpc/issues/22244) we need a the |
|
|
|
|
# grpc_shutdown_blocking() counterpart for this call. Otherwise, the gRPC |
|
|
|
|
# library won't shutdown cleanly. |
|
|
|
|
grpc_init() |
|
|
|
|
|
|
|
|
|
_grpc_aio_initialized = False |
|
|
|
|
with _grpc_initialization_lock: |
|
|
|
|
# Marks this function as called |
|
|
|
|
if _grpc_aio_initialized: |
|
|
|
|
return |
|
|
|
|
else: |
|
|
|
|
_grpc_aio_initialized = True |
|
|
|
|
|
|
|
|
|
# Picks the engine for gRPC AsyncIO Stack |
|
|
|
|
for engine_type in AsyncIOEngine: |
|
|
|
|
if engine_type.value == _GRPC_ASYNCIO_ENGINE: |
|
|
|
|
grpc_aio_engine = engine_type |
|
|
|
|
break |
|
|
|
|
if grpc_aio_engine is None or grpc_aio_engine is AsyncIOEngine.DEFAULT: |
|
|
|
|
grpc_aio_engine = AsyncIOEngine.CUSTOM_IO_MANAGER |
|
|
|
|
|
|
|
|
|
# Anchors the event loop that the gRPC library going to use. |
|
|
|
|
_grpc_aio_loop = asyncio.get_event_loop() |
|
|
|
|
_event_loop_thread_ident = threading.current_thread().ident |
|
|
|
|
|
|
|
|
|
if grpc_aio_engine is AsyncIOEngine.CUSTOM_IO_MANAGER: |
|
|
|
|
# Activates asyncio IO manager. |
|
|
|
|
# NOTE(lidiz) Custom IO manager must be activated before the first |
|
|
|
|
# `grpc_init()`. Otherwise, some special configurations in Core won't |
|
|
|
|
# pick up the change, and resulted in SEGFAULT or ABORT. |
|
|
|
|
install_asyncio_iomgr() |
|
|
|
|
|
|
|
|
|
# TODO(https://github.com/grpc/grpc/issues/22244) we need a the |
|
|
|
|
# grpc_shutdown_blocking() counterpart for this call. Otherwise, the gRPC |
|
|
|
|
# library won't shutdown cleanly. |
|
|
|
|
grpc_init() |
|
|
|
|
|
|
|
|
|
# Timers are triggered by the Asyncio loop. We disable |
|
|
|
|
# the background thread that is being used by the native |
|
|
|
|
# gRPC iomgr. |
|
|
|
|
grpc_timer_manager_set_threading(False) |
|
|
|
|
|
|
|
|
|
# gRPC callbaks are executed within the same thread used by the Asyncio |
|
|
|
|
# event loop, as it is being done by the other Asyncio callbacks. |
|
|
|
|
Executor.SetThreadingAll(False) |
|
|
|
|
else: |
|
|
|
|
# TODO(https://github.com/grpc/grpc/issues/22244) we need a the |
|
|
|
|
# grpc_shutdown_blocking() counterpart for this call. Otherwise, the gRPC |
|
|
|
|
# library won't shutdown cleanly. |
|
|
|
|
grpc_init() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def grpc_aio_loop(): |
|
|
|
|