在线程中运行bash脚本而不阻塞主循环

时间:2013-06-15 18:42:58

标签: python multithreading bash

我有一个python程序,当我在一个线程中运行一个bash脚本并显示一些消息时,我想要一个进度条脉动。

当我单击一个按钮时,线程开始启动脚本,但消息和进度条仅在线程完成时响应,仅显示最后一条消息。

阅读,我明白我阻止了主循环,但我无法弄清楚如何解决这个问题。

我的程序的简化代码,问题是在调用“on_fixme_button_pressed”时:

from gi.repository import Gtk, Gdk, Pango, GObject, GLib
import os, sys
import xml.etree.ElementTree as etree
from urllib.request import urlopen
from subprocess import Popen
import threading


UI_FILE = "remendo_gtk.ui"
#UI_FILE = "/usr/local/share/remendo_gtk/ui/remendo_gtk.ui"

GObject.threads_init()

class GUI:

    def __init__(self):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        self.window = self.builder.get_object('remendo')
        self.event_treeview = self.builder.get_object('event_treeview')
        self.event_info = self.builder.get_object('event_info')
        self.progressbar = self.builder.get_object('progressbar')
        self.progressbar_lock = threading.Lock()

        self.selected_event = ''
        self.url_script = ''
        self.local_script = ''
        self.window.connect("destroy", lambda _: Gtk.main_quit())
        self.set_event_list()

        self.window.show_all()

    def pulse_progressbar(self):
        if threading.active_count() > 1:
            self.progressbar.pulse()
            return True

        self.progressbar.set_fraction(0.0)
        self.progressbar_lock.release()
        return False

    def on_fixme_button_clicked(self, button):
        self.event_info.set_label("Fixing now...")
        script = threading.Thread(target=self.run_script(), args=(self,))
        script.start()

        if self.progressbar_lock.acquire(False):
            GLib.timeout_add(250, self.pulse_progressbar)

    def run_script(self):
        try:
            self.local_script = '/tmp/%s.sh' % self.selected_event.replace(" ", "_")
            script = urlopen(self.url_script)
            localscript = open(self.local_script, 'wb')
            localscript.write(script.read())
            localscript.close()

            command = ['bash', self.local_script]
            p = Popen(command)
            p.communicate()

            #self.event_solved()
            self.event_info.set_label("My work is done. Good day!")
        except:
            self.event_info.set_label("Script failed: %s" % self.local_script)

        return False


def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

4 个答案:

答案 0 :(得分:1)

如果您使用subprocess.Popen,则等待返回的处理程序.wait()。您可以使用.poll()调查流程是否已完成[和退出代码],或与.communicate()进行交互(标准输入/输出)。

文档可在此处找到: http://docs.python.org/2/library/subprocess.html#module-subprocess

你试过什么?

答案 1 :(得分:0)

我真的不确定它会有所帮助,但我建议你看一下Pexpect模块:http://pexpect.sourceforge.net/pexpect.html

据我所知,它是系统调用的更复杂的“启动器”。

答案 2 :(得分:0)

最后使用GObject.timeout_add解决了使用线程类中的变量更新消息状态以了解进程何时完成,以及使用@ johan-lundberg建议的.communicate()选项

答案 3 :(得分:0)

至少有两个问题:

  • target=self.run_script()不正确:它立即运行该功能。删除(),将方法作为参数传递而不是调用它。
  • 您在没有后台线程保护的情况下调用GUI方法(在self.event_info.set_label上)。解决此问题的最简单方法是使用set_label调用idle_add()

    Gobject.idle_add(self.event_info.set_label, msg) # in a background thread
    

    使用idle_add是安全的,因为模块顶部有Gobject.init_threads()

另见Threading in Gtk python

I am using a separate thread to run my code, but the application (or the UI) hangs.(gtk2)

相关问题