问题:从远程 HTTP 源加载数据时不阻止 GTK UI 的正确方法是什么?
背景:
我正在为 Ubuntu Unity 开发加密货币价格指标。我已经修改了原始项目,以便它可以同时运行多个代码。
从原理上讲,它的工作原理如下:
主线程找到要加载的每个代码,并为每个代码启动一个 GTK libAppindicator 实例(Indicator)。然后每个指标加载一个类,该类从远程 API 检索代码数据并将其反馈给指标。
但是,我注意到 UI 在不规则的时间间隔变得无响应。我认为这是因为 HTTP 请求(带有请求库)被阻塞。所以我决定在自己的线程中启动每个指标,但是一旦代码全部加载,同样的问题仍然会发生。(我不明白为什么,如果某些东西在它自己的线程上,它不应该阻塞主线程?)
然后我尝试用 grequests 替换请求,但是我无法让它工作,因为回调似乎永远不会被调用。似乎也有类似 Promise 的东西,但所有这些的文档看起来已经过时且不完整。
代码:
# necessary imports here
class Coin(Object):
self.start_main()
self.instances = []
def start_main(self):
self.main_item = AppIndicator.Indicator.new(name, icon)
self.main_item.set_menu(self._menu()) # loads menu and related actions (code omitted)
def add_indicator(self, settings=None):
indicator = Indicator(self, len(self.instances), self.config, settings)
self.instances.append(indicator)
nt = threading.Thread(target=indicator.start())
nt.start()
def _add_ticker(self, widget): # this is clickable from the menu (code omitted)
self.add_indicator('DEFAULTS')
class Indicator():
instances = []
def __init__(self, coin, counter, config, settings=None):
Indicator.instances.append(self)
def start(self):
self.indicator = AppIndicator.Indicator.new(name + "_" + str(len(self.instances)), icon)
self.indicator.set_menu(self._menu())
self._start_exchange()
def set_data(self, label, bid, high, low, ask, volume=None):
# sets data in GUI
def _start_exchange(self):
exchange = Kraken(self.config, self)
exchange.check_price()
exchange.start()
class Kraken:
def __init__(self, config, indicator):
self.indicator = indicator
self.timeout_id = 0
def start(self):
self.timeout_id = GLib.timeout_add_seconds(refresh, self.check_price)
def stop(self):
if self.timeout_id:
GLib.source_remove(self.timeout_id)
def check_price(self):
res = requests.get('https://api.kraken.com/0/public/Ticker?pair=XXBTZUSD')
data = res.json()
self._parse_result(data['result'])
def _parse_result(self, data):
# code to parse json result
self.indicator.set_data(label, bid, high, low, ask)
coin = Coin()
Gtk.main()