11

好吧,伙计们关于 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 搜索它。我找到它并尝试安装它,但由于链接错误,它失败了(我使用超级用户进行安装)。接下来,我从他们的存储库下载并安装了它。我得到了这个示例,我运行它并得到了一些错误,因为他们的核心模块中缺少参数。我真的不知道是哪个错误导致我从不同的 PC 写这个我会更新是尽快。如果其他人可以测试它,我将不胜感激。

4

1 回答 1

13

As of 2020, the gbulb library appears to be unmaintained. Anyone wishing to integrate asyncio and GTK should only consider the second part of the answer (showing asyncio running in a dedicated thread) or take a look at asyncio-glib, which integrates asyncio and GTK using an approach more minimalistic and robust than that taken by gbulb.

Original answer follows below.


The gbulb library is designed to provide a connector between the asyncio event loop as specified by PEP 3156 and the GLib main loop implementation. However, the current master of gbulb is broken for asyncio as shipped with Python 3.4. To fix this, you can check out this fork instead of the master. (The problem was later fixed upstream.)

With a working gbulb, it is trivial to modify your example to both accept incoming connections and run 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()

Another possibility is to run the asyncio event loop in a different thread:

#!/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()

This has the advantage of not requiring gbulb at all (it is not clear how well gbulb has been tested in production). One does need to be careful, however, to use thread-safe functions to communicate between the GUI (main) thread and the asyncio thread. This means using loop.call_soon_threadsafe or asyncio.run_coroutine_threadsafe to submit things to asyncio from GTK, and GLib.idle_add to submit things to GTK from asyncio.

于 2014-11-03T17:52:30.150 回答