Как выбрать асинхронный или синхронный вариант метода в Python? - PullRequest
1 голос
/ 10 июня 2019

Предположим, у меня есть класс, который используется для выполнения операций ввода-вывода:

class CommunicationStack:
    def __init__(self, socket):
        self.socket = socket

    def sync_get_data(self):
        ...

    def sync_send_data(self):
        ...

    async def async_get_data(self):
        ...

    async def async_send_data(self):
        ...

Как вы можете видеть, он имеет вариант синхронизации и асинхронности для тех же операций, но было бы немного неудобно писатьasync_get_data или sync_get_data вручную.Я ищу умный способ иметь такой же интерфейс, как

def get_data(self):
    ...  # call sync variant or return an awaitable, depending on caller type

def send_data(self):
    ...  # call sync variant or return an awaitable, depending on caller type

, чтобы его можно было удобно использовать, например:

stack = CommunicationStack(...)

def thread_procedure():
    data = stack.get_data()  # get_data returns data

async def task_procedure():
    data = await stack.get_data()  # get_data returns an awaitable

Я считаю, что это можно сделать каким-то хитрым способом сосмотры или некоторая черная магия :

def is_caller_coroutine():
    return sys._getframe(2).f_code.co_flags & 0x380

, чтобы проверить, является ли вызывающая функция сопрограммой или функцией, но это кажется плохим дизайном, чтобы портить кишки питона.


Вопрос в том, как правильно выбрать подходящий вариант?Или есть лучший способ спроектировать все, например, с использованием адаптеров или разработкой двух независимых классов AsyncCommunicationStack и SyncCommunicationStack?

1 Ответ

1 голос
/ 10 июня 2019

Если вы хотите вызывать асинхронные функции так же, как и обычные, вас может заинтересовать использование gevent .

asyncio хочет, чтобы вы явно помечали функции как async иявно использовать await везде, где происходит асинхронная работа.Другими словами, asyncio хочет, чтобы у вас были разные интерфейсы для синхронизации и асинхронного кода.

Это преднамеренное решение , принятое для борьбы с проблемами параллелизма, которые гораздо труднее достичь при асинхронной природекод скрыт (как в gevent).

Так что да - два разных независимых класса AsyncCommunicationStack и CommunicationStack - это путь, если вы хотите поддерживать оба мира.Несмотря на то, что у вас есть асинхронная версия, вы можете привести к написанию критического кода и синхронизировать его, просто запустив его с помощью asyncio.run () .Проблема только в том, что после этого вы не сможете вернуться в асинхронный мир.

...