在GTK主循环中运行的Asyncio调用
问题描述
好的关于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_threadsafe
或asyncio.run_coroutine_threadsafe
从GTK向Asyncio提交内容,使用GLib.idle_add
从Asyncio向GTK提交内容。
相关文章