在GTK主循环中运行的Asyncio调用

2022-02-27 00:00:00 python python-asyncio gtk3 gtk

问题描述

好的关于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()

编辑:

好的,我应该用gbulb写下我的经历。 首先,我使用PIP3进行了搜索。我找到了它,并试图安装它,但由于链接错误,它失败了(我正在使用超级用户进行安装)。 接下来,我从他们的存储库中下载并安装了它。我得到了这个example,我运行了它,因为他们的核心模块中缺少参数,所以出现了一些错误。我不知道是哪个错误,因为我是从不同的PC编写这篇文章的,我会尽快更新。另外,如果其他人能测试一下,我将不胜感激。


解决方案

自2020年起,gbulb库显示为unmaintained。任何希望集成asyncio和gtk的人都应该只考虑答案的第二部分(显示asyncio在专用线程中运行)或查看asyncio-glib,它使用比gbulb更简约和健壮的方法集成了asyncio和gtk。

原始答案如下。


gbulb library旨在提供PEP3156指定的异步事件循环和Glib主循环实现之间的连接器。但是,gbulb的当前主机在随Python3.4一起提供的异步CIO中已损坏。若要解决此问题,您可以签出this fork,而不是签出主文件。(该问题稍后已在上游修复。)

使用有效的gbulb,修改示例以接受传入连接并运行GTK:

非常简单
#!/usr/bin/python3

import gi
gi.require_version("Gtk", "3.0")

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()

另一种可能是在不同的线程中运行异步事件循环:

#!/usr/bin/python3

import asyncio, threading

import gi
gi.require_version("Gtk", "3.0")

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(主)线程和异步线程之间通信时需要小心。这意味着使用loop.call_soon_threadsafeasyncio.run_coroutine_threadsafe从GTK向Asyncio提交内容,使用GLib.idle_add从Asyncio向GTK提交内容。

相关文章