Python:执行HTTP请求时不阻塞GTK UI的正确方法
问:在从远程HTTP源加载数据时,不阻止GTK UI的正确方法是什么 背景: 我正在做一件事。我修改了原始项目,使其可以同时运行多个ticker 示意图上,它的工作原理如下: 主线程找到要加载的每个ticker,并为每个ticker启动一个GTK libAppindicator实例(Indicator)。然后,每个指示器加载一个类,该类从远程API检索股票代码数据并将其反馈给指示器 然而,我注意到UI在不规则的时间间隔内变得不负责任。我假设这是因为HTTP请求(带有请求库)被阻塞。所以我决定在自己的线程中启动每个指示器,但一旦所有的指示器都加载完毕,同样的问题仍然会发生。(我不明白为什么,如果某个线程本身有问题,它就不应该阻塞主线程?) 然后我尝试用grequests替换请求,但是我无法让它工作,因为回调似乎从未被调用过。似乎也有类似承诺的东西,但所有这些的文档看起来都过时了,而且不完整 代码:Python:执行HTTP请求时不阻塞GTK UI的正确方法,python,gtk,python-requests,gtk3,grequests,Python,Gtk,Python Requests,Gtk3,Grequests,问:在从远程HTTP源加载数据时,不阻止GTK UI的正确方法是什么 背景: 我正在做一件事。我修改了原始项目,使其可以同时运行多个ticker 示意图上,它的工作原理如下: 主线程找到要加载的每个ticker,并为每个ticker启动一个GTK libAppindicator实例(Indicator)。然后,每个指示器加载一个类,该类从远程API检索股票代码数据并将其反馈给指示器 然而,我注意到UI在不规则的时间间隔内变得不负责任。我假设这是因为HTTP请求(带有请求库)被阻塞。所以我决定在自
在
线程中运行HTTP
可以更好地显示代码。可能在新线程中,您使用GUI元素在GUI中阻止mainloop
,或者您向主线程发送数据,当GUI接收数据时,它阻止mainloop
。我检查了您的大多数文件,发现import threading
仅在coin/indicator.py
中存在,但您从未使用它创建新线程。那个么你们在哪里创建那个些线程呢?我不确定你们应该在线程中运行指示器,因为它是ogf GUI的一部分。线程应该只下载数据。Gtk.main()
运行循环,从系统获取事件,将事件发送到小部件,重新绘制小部件。如果它被阻止了,那么它就不能刷新窗口小部件,并且看起来它冻结了。它一直工作,直到你关上窗户。您必须在Gtk.main()
之前或使用GUI中的按钮启动GUI之后运行其他线程。或者您可以使用thread.Timer()
在Gtk.main()
之前创建它,但它将在Gtk.main()
启动之后启动。
# 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()