3

问题:从远程 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()
4

0 回答 0