如何在不阻塞的情况下使用 mpd.idle() 从 GTK 轮询 MPD

Posted

技术标签:

【中文标题】如何在不阻塞的情况下使用 mpd.idle() 从 GTK 轮询 MPD【英文标题】:How to poll MPD from GTK with mpd.idle() without blocking 【发布时间】:2020-01-29 10:11:36 【问题描述】:

我想使用 MPD 的空闲功能等待任何更改,然后使用 Python 在 GTK GUI 中显示它们。问题是,当我使用 MPD 的空闲功能时,GUI 似乎阻塞并变得无响应(当更改歌曲时,GTK 窗口变得无响应)。当我删除 self.mpd.idle() 时,它可以工作,但是该函数一直在运行,我认为这是不必要的。

解决这个问题的最佳方法是什么?

不工作 我最初的做法:

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 10
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)
        self.window.show_all()

        GLib.idle_add(self.get_current_song)
        Gtk.main()

    def get_current_song(self):
        self.mpd.idle()
        print(self.mpd.currentsong())
        return True

app = GUI()

不工作 我使用this 的第二种方法。仍然得到相同的结果。

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 1
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)

        self.window.show_all()
        self.thread = threading.Thread(target=self.idle_loop)
        self.thread.daemon = True
        self.thread.start()
        Gtk.main()

    def get_songs(self):
        print(self.mpd.currentsong())
        self.mpd.idle()
        return True

    def idle_loop(self):
        GLib.idle_add(self.get_songs)

app = GUI()

工作中 省略 GLib.idle_add() 函数似乎是一个解决方案。但我不知道这是否是“正确”的方式。不知道为什么 GLib.idle_add() 搞砸了它并且不使用它感觉不对,因为它在文档中提到。

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 1
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)

        self.window.show_all()
        self.thread = threading.Thread(target=self.get_songs)
        self.thread.daemon = True
        self.thread.start()
        Gtk.main()

    def get_songs(self):
        self.mpd.idle()
        print(self.mpd.currentsong())

app = GUI()

【问题讨论】:

你可以使用threading.Thread让歌曲获取任务同时运行吗? 线程是错误问题的错误解决方案。它不会阻止the function keeps getting run all the time which I find unnecessary 问题。 我尝试使用 OP 中提到的线程模块(我发现this。仍然有同样的问题。然后我省略了 GLib.idle_add() 函数,它现在有点工作了。我不知道这是否是“正确的方式”,没有使用 GLib.idle_add() 函数。 您应该每次都将函数添加到GLib.idle_add,即每当您想要对GUI进行一些更改时。 但将其添加到 GLib.idle_add 会导致锁定。这就是它不起作用的原因。 【参考方案1】:

让我们在这里使用threading 模块。 如本文所述:https://pygobject.readthedocs.io/en/latest/guide/threading.html,我们可以制作如下代码:

import gi
from threading import Thread
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 10
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)
        self.window.show_all()

        thread = Thread(target=self.get_current_song, args=())
        thread.start()
        Gtk.main()

    def get_current_song(self):
        self.mpd.idle()
        print(self.mpd.currentsong())
        return True

app = GUI()

【讨论】:

谢谢。我摆脱了 GLib.idle_add() 函数,它不再对歌曲更改无响应。我更新了 OP。

以上是关于如何在不阻塞的情况下使用 mpd.idle() 从 GTK 轮询 MPD的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 C++/C 中的阻塞函数的情况下将值从线程返回到主函数

如何使用 ROOM 库在不阻塞 UI 的情况下将数千条记录从本地数据库加载到 recyclerview

Flutter:如何在不阻塞 UI 的情况下异步地从资产中读取文件

Java 执行器:当任务完成时,如何在不阻塞的情况下得到通知?

如何在不阻塞的情况下发出请求(使用 asyncio)?

如何在不阻塞 UI 的情况下创建 UIView