Решение, принятое некоторыми системами на основе циклов событий (по существу, решение, которое вы ссылаетесь через API QCoreApplication.processEvents
Qt), состоит в том, чтобы выполнить повторный вход в основной цикл. В Twisted выражении это будет означать что-то вроде (не рабочий код):
def my_expensive_task_that_cannot_be_asynchronous():
@inlineCallbacks
def do_work(units):
for unit in units:
yield do_one_work_asynchronously(unit)
work = do_work(some_work_units())
work.addBoth(lambda ignored: reactor.stop())
reactor.run()
def main():
# Whatever your setup is...
# Then, hypothetical event source triggering your
# expensive function:
reactor.callLater(
30,
my_expensive_task_that_cannot_be_asynchronous,
)
reactor.run()
Обратите внимание, как есть дваreactor.run
вызовы в этой программе. Если у Twisted был цикл событий повторного входа, этот второй вызов снова начнет вращать реактор и не вернется, пока не встретится соответствующий вызов reactor.stop
. Реактор будет обрабатывать все события, о которых он знает, а не только те, которые генерируются do_work
, и поэтому у вас будет такое поведение, которое вы желаете.
Для этого требуется цикл событий повторного входа, потому что my_expensive_task_...
уже вызывается контуром реактора. Контур реактора находится в стеке вызовов. Затем вызывается reactor.run
и петля реактора теперь находится в стеке вызовов снова. Таким образом, применяются обычные проблемы: цикл событий не может быть оставлен над состоянием в его кадре (в противном случае он может быть недействительным к моменту завершения вложенного вызова), он не может оставить свое состояние экземпляра непоследовательным во время любых вызовов другому коду и т. Д.
У витой пары нет цикла повторного входа. Это признак, который был рассмотрен и, по крайней мере в прошлом, явно отклонен. Поддержка этих функций приносит большую сложность (описанную выше) к реализации и приложения. Если цикл события повторен, то становится очень трудно избежать необходимости повторного включения всех программных кодов.Это отрицает одно из основных преимуществ кооперативного подхода к многозадачности. Twisted принимает на параллелизм (вам гарантировано, что ваши функции не будут повторно введены).
Итак, при использовании Twisted это решение отсутствует.
Я не знаю другого решения, которое позволило бы продолжить выполнение этого кода в потоке реактора. Вы упомянули, что данный код глубоко вложен в какой-то другой синхронный код. Другие варианты, которые приходят на ум:
- сделать синхронный код, способным справиться с асинхронными вещами
- фактора дорогих частями, и вычислить их, а затем передать результат в к остальной части коды
- запустить все этого кода, а не только вычислительно дорогой части, в другом потоке
это помогло бы, если бы я мог вернуть результат 'my_func', как отложенный, но, как я сказал, он похоронен глубоко в синхронном коде, и ret Урн отложен, я должен переписать все это, чтобы пузырить отложенные до самого цикла событий. – immerrr
Я обновил вопрос, чтобы отразить, что время единственной итерации в порядке, а также то, что все время итерации слишком велико. – immerrr