Можно ли конвертировать concurrent.futures.Future в asyncio.Future? - PullRequest
0 голосов
/ 08 января 2019

Я практикую asyncio после написания многопоточного кода много лет.

Заметил что-то, что мне показалось странным. И в asyncio, и в concurrent есть Future объект.

from asyncio import Future
from concurrent.futures import Future

Угадай, у каждого своя роль ...

У меня вопрос, могу ли я перевести concurrent.future.Future на asyncio.Future (или наоборот)?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Мой вопрос: могу ли я перевести concurrent.future.Future на asyncio.Future (или наоборот)?

Если под «переносом» вы подразумеваете «преобразование одного в другое», то да, это возможно, хотя для устранения несоответствия импеданса между подходами может потребоваться определенная работа.

Чтобы преобразовать concurrent.futures.Future в asyncio.Future, вы можете позвонить asyncio.wrap_future. Возвращенное будущее asyncio ожидаемо в цикле событий asyncio и завершится, когда завершится базовое будущее потоков. Это эффективный способ реализации run_in_executor.

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

def to_concurrent(fut, loop):
    async def wait():
        await fut
    return asyncio.run_coroutine_threadsafe(wait(), loop)

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

0 голосов
/ 08 января 2019

concurrent.futures.Future - это объект, который мы используем для написания асинхронного кода, основанного на потоках ОС или процессах ОС, наряду с другими вещами, которые concurrent.futures предоставляет нам модуль.

asyncio.Future - это объект, который мы используем для написания асинхронного кода, основанного на сопрограммах и других вещах, которые asyncio предоставляет нам модуль.

Другими словами concurrent.futures и asyncio пытаются решить одну и ту же задачу, но разными способами. Решение одной и той же задачи означает, что многие вещи будут похожи в подходе на основе потоков / процессов и подходе на основе сопрограмм. Например, взгляните на asyncio.Lock и threading.Lock - похоже, но отличается.

Возможен ли переход между разными подобными объектами? Нет, это не так.

Существенная разница между asyncio и потоковыми модулями делает невозможным сотрудничество:

  • В asyncio вы должны await вещи, чтобы приостановить поток выполнения и разрешить выполнение других сопрограмм.

  • В потоковых модулях выполнение приостановлено из-за приостановки всего потока.

Например, когда вы пишете код на основе потоков, вы пишете:

future = concurrent.futures.Future()
# ...
result = future.result()  # acts like time.sleep blocking whole thread

Но в asyncio вы не должны блокировать поток, вы должны вернуть управление в цикл обработки событий:

future = asyncio.Future()
# ...
result = await future  # block current execution flow returning control to event loop 
                       # without blocking thread,
                       # current flow will be resumed later
...