Асинчио звонит в основной цикл Gtk

Вопрос Okey решает вопрос о asyncio и Gtk +. Как запустить код ниже в цикле Gtk.main? Я искал пример, но не смог найти.

#!/usr/bin/python3.4

import asyncio

@asyncio.coroutine
def client_connected_handler(client_reader, client_writer):
    print("Connection received!")
    client_writer.write(b'Hello')
    while True:
        data = yield from client_reader.read(8192)
        if not data:
            break
        if 'EXIT' in data.decode():
            print("Closing server")
            break   
        print(data)
        client_writer.write(data)
    print('Server is closed')


loop = asyncio.get_event_loop()
Server=asyncio.start_server(client_connected_handler, 'localhost', 2222)
server=loop.run_until_complete(Server)
loop.run_forever()

EDIT:

Okey Я должен написать свой эксперимент с gbulb. Сначала я обыскал его с помощью pip3. Я нашел его и попытался установить его, но он потерпел неудачу (я использовал суперпользователя для установки) из-за плохих ссылок. Затем я загрузил его из своего репозитория и установил его. Я получил это example Я запустил его и получил некоторые ошибки для отсутствующих аргументов в своем основном модуле. Я не знаю, действительно ли это ошибка, потому что я пишу это с другого ПК, который буду обновлять, как можно скорее. Также я был бы признателен, если бы кто-нибудь еще мог его протестировать.

Ответ 1

РЕДАКТИРОВАТЬ
По состоянию на 2019 г. библиотека gbulb, по-видимому, не поддерживается. Любой, кто хочет интегрировать Asyncio и GTK, вероятно, должен рассмотреть только вторую часть ответа.

Библиотека gbulb предназначена для обеспечения связующего звена между циклом событий асинхронности, как указано в PEP 3156, и реализацией основного цикла GLib. Тем не менее, текущий мастер gbulb работает для asyncio, как поставляется с Python 3.4. Чтобы исправить это, вы можете проверить эту вилку вместо мастера. (Впоследствии проблема была исправлена.)

С работающим gbulb тривиально изменить ваш пример так, чтобы он принимал входящие соединения и запускал GTK:

#!/usr/bin/python3

import asyncio, gbulb
from gi.repository import Gtk
asyncio.set_event_loop_policy(gbulb.GLibEventLoopPolicy())

@asyncio.coroutine
def client_connected_handler(client_reader, client_writer):
    print("Connection received!")
    client_writer.write(b'Hello')
    while True:
        data = yield from client_reader.read(8192)
        if not data:
            break
        if 'EXIT' in data.decode():
            print("Closing server")
            break   
        print(data)
        client_writer.write(data)
    print('Server is closed')

loop = asyncio.get_event_loop()
loop.run_until_complete(
    asyncio.start_server(client_connected_handler, 'localhost', 2222))

w = Gtk.Window()
w.add(Gtk.Label('hey!'))
w.connect('destroy', Gtk.main_quit)
w.show_all()

loop.run_forever()

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

#!/usr/bin/python3

import asyncio, threading
from gi.repository import Gtk

async def client_connected_handler(client_reader, client_writer):
    # ... unchanged ...

def run_asyncio():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(
        asyncio.start_server(client_connected_handler, 'localhost', 2222))
    loop.run_forever()

threading.Thread(target=run_asyncio).start()

w = Gtk.Window()
w.add(Gtk.Label('hey!'))
w.connect('destroy', Gtk.main_quit)
w.show_all()

Gtk.main()

Преимущество этого в том, что gbulb вообще не требуется (неясно, насколько хорошо gbulb был протестирован в производстве). Однако необходимо соблюдать осторожность, чтобы использовать потокобезопасные функции для связи между основным потоком GUI и потоком asyncio. Это означает использование loop.call_soon_threadsafe или asyncio.run_coroutine_threadsafe для отправки вещей в asyncio из GTK и GLib.idle_add для отправки вещей в GTK из asyncio.