如何在不阻塞的情况下使用 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 的情况下异步地从资产中读取文件