Мне нужно преобразовать синхронную функцию в приложении PyGTK для использования асинхронной библиотеки.
Библиотека использует timeout_add
и io_add_watch
с обратными вызовами (см. пример ниже). Он не использует потоки Python, поэтому библиотека python threading
работать не будет.
Есть ли что-то вроде threading.Event
в PyGTK/GLib, которое позволило бы мне блокировать внутри функции до тех пор, пока асинхронная библиотека не вызовет обратный вызов с возвращаемыми данными?
Старая функция:
def sync_fetch():
return 'The Result'
Пример асинхронной библиотеки:
def async_fetch(callback):
assert callable(callback)
gobject.timeout_add(100, lambda: callback('The Result'))
Возможная структура: (например, threading.Event
)
class AsyncToSyncFetch(object):
def __init__(self):
self._event = Event()
self._result = None
def _set_result(self, result):
self._result = result
self._event.set()
def sync_fetch(self):
async_fetch(callback=self._set_result)
# block here until _event.set() is called
self._event.wait()
return self._result
Я разместил здесь небольшую тестовую программу GTK (используя threading.Event
, время ожидания истекло): https://gist.github.com/anonymous/206d1cc7218994e620a7#file-gtk_async_to_sync-py
Обновление — возможное решение: я нашел решение с использованием вложенных основных циклов в этом ответе. Но это можно использовать только в одной области за раз в основном цикле, поскольку функция «разблокировать» является глобальной и не соответствует функции «блокировки». Из gtk_main: "gtk_main_quit() сделает самый внутренний вызов возврата основного цикла."
def sync_fetch(self):
# start the async function first
async_fetch(callback=self._result_loaded)
# nest another mainloop, which blocks
# until gtk.main_quit() is called
gtk.main()
# this will get loaded before we resume
return self._result
# this is the callback from the async function
def _result_loaded(self, result):
print('result loaded')
# it saves a variable accessible from sync_fetch
self._result = result
# exit the nested main loop, allowing sync_fetch to resume
gtk.main_quit()
threading
не работает, потому что GLib использует собственный тип многопоточности. Любые блоки, добавленные библиотекойthreading
(кроме нового потока Python), блокируют весь основной цикл, включая источники событий. - person Oleg   schedule 05.03.2015