Python: как заблокировать PyGTK во время ожидания обратного вызова timeout_add?

Мне нужно преобразовать синхронную функцию в приложении 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()

person Oleg    schedule 05.03.2015    source источник
comment
Насколько я помню, вы должны просто использовать нормальные языковые конструкции для межпотокового взаимодействия.   -  person doublep    schedule 05.03.2015
comment
Библиотека Python threading не работает, потому что GLib использует собственный тип многопоточности. Любые блоки, добавленные библиотекой threading (кроме нового потока Python), блокируют весь основной цикл, включая источники событий.   -  person Oleg    schedule 05.03.2015