线程GTK中蟒(Threading in Gtk python)

2019-06-26 23:42发布

所以我忙着写,需要一定的时间OUF之后,从网站检查更新的应用程序,我使用python的跟Gtk +3

main.py文件

class Gui:
    ...
    def on_update_click():
        update()

app=Gui()
Gtk.main()

update.py文件

def update():
    #check site for updates
    time.sleep(21600) #check again in 6hrs

我怀疑我将不得不使用线程。 我的想法是:

Gtk.main()运行在主线程。

当用户点击更新按钮,更新()在后台运行。 #thread 2

我想正确的或有我错过了什么?

编辑:好的,
on_update_click功能:

            Thread(target=update).start(). 

K,电脑也不会冻结了:d

那么现在情况是,只有当我关闭Gtk.main()不更新线程才开始。 这是很好的,是继续当UI被关闭更新,但我也喜欢它启动时,用户界面是向上。

Answer 1:

于是,我终于设法得到它的工作。 我需要说的:

from gi.repository import Gtk,GObject

GObject.threads_init()
Class Gui:
    .....
    ......
    def on_update_click():
            Thread(target=update).start()

起初,我用:

thread.start_new_thread(update())

在on_update_click功能。 正如我提到的塞巴斯蒂安JF这是不正确的,因为这会立即调用这个线程。 这冻结了我的整个计算机。

然后我就补充道:

Thread(target=update).start()

该on_update_clicked功能才做一次主线程Gtk.main()被关闭。 所以线程不同时运行。

通过添加:GObject.threads_init()

:这允许的线程串行方式运行Python解释器中的Gtk主题 !



Answer 2:

thread.start_new_thread(update())是错误的。 它调用update()立即在主线程和你不应该使用thread直接模块; 使用threading模块来代替。

你可以调用threading.current_thread()来找出哪些线程执行update()

要简化您的代码可以运行在主线程中所有的GTK代码,并使用阻塞操作来检索网页和在后台线程运行。

基于从GTK + 3教程扩展示例 :

#!/usr/bin/python
import threading
import urllib2
from Queue import Queue

from gi.repository import Gtk, GObject

UPDATE_TIMEOUT = .1 # in seconds

_lock = threading.Lock()
def info(*args):
    with _lock:
        print("%s %s" % (threading.current_thread(), " ".join(map(str, args))))

class MyWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Hello World")

        self.button = Gtk.Button(label="Click Here")
        self.button.connect("clicked", self.on_button_clicked)
        self.add(self.button)

        self.updater = Updater()
        self._update_id = None
        self.update()

    def on_button_clicked(self, widget):
        info('button_clicked')
        self.update()

    def update(self):
        if self._update_id is not None: 
            GObject.source_remove(self._update_id)

        self.updater.add_update(self.done_updating) # returns immediately
        # call in UPDATE_TIMEOUT seconds
        self._update_id = GObject.timeout_add(
            int(UPDATE_TIMEOUT*1000), self.update)

    def done_updating(self, task_id):
        info('done updating', task_id)
        self.button.set_label("done updating %s" % task_id)


class Updater:
    def __init__(self):
        self._task_id = 0
        self._queue = Queue(maxsize=100) #NOTE: GUI blocks if queue is full
        for _ in range(9):
            t = threading.Thread(target=self._work)
            t.daemon = True
            t.start()

    def _work(self):
        # executed in background thread
        opener = urllib2.build_opener()
        for task_id, done, args in iter(self._queue.get, None):
            info('received task', task_id)
            try: # do something blocking e.g., urlopen()
                data = opener.open('http://localhost:5001').read()
            except IOError:
                pass # ignore errors

            # signal task completion; run done() in the main thread
            GObject.idle_add(done, *((task_id,) + args))

    def add_update(self, callback, *args):
        # executed in the main thread
        self._task_id += 1
        info('sending task ', self._task_id)
        self._queue.put((self._task_id, callback, args))

GObject.threads_init() # init threads?

win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()

Gtk.main()

注: GObject.idle_add()是从不同的线程调用的唯一GTK的相关功能。

另请参见多线程GTK程序-第1部分:误解 。



Answer 3:

线程是解决这个问题的第一种方式。 您可以创建线程和运行长期运行阻塞线程内部功能(和你的GUI不会挂断电话)。

另一种方法是使用python-GIO(GObject的-IO),或有可能与GLib的主回路工作(另一个库使用异步联网比如像他们这样做与扭曲 )。 这种做法有点不同,并使用非阻塞套接字操作。 你的主循环,可以使一个回调时,从套接字数据(网站你轮询)将可阅读。 不幸的是GIO没有高层次的HTTP API,所以你可以使用GSocketClient和手动创建HTTP请求结构。



文章来源: Threading in Gtk python