通过子进程执行异步任务,无需线程阻塞

时间:2017-11-03 11:32:03

标签: multithreading python-2.7 asynchronous tkinter subprocess

我的代码的目的是通过tkinter生成一个进度条,虽然我的进度条正在进行,但我希望通过子进程调用7-zip来提取.7z文件。

解压缩7-Zip文件后,我想关闭计算机。第一个问题是,提取7-Zip文件的行之后的代码行,无需等待即可执行和关闭计算机。

鉴于此,我需要等到提取完成后再继续。这个问题的一个问题是,我无法阻止任何线程,因为我的进度条仍在运行。使用我当前的代码,我可以等待提取,但进度条不会出现,直到提取完成,因为所有线程都被阻止。

在某种程度上说,我是如何实现目标的呢?

这是我的进度条形码:

class FinishSetup(tk.Toplevel):

    # progress bar to simulate finishing set up
    def __init__(self, *args, **kwargs):
        tk.Toplevel.__init__(self, *args, **kwargs)
        self.progress = ttk.Progressbar(self, orient="horizontal",
            length=200, mode="determinate")
        self.progress.pack()

        self.bytes = 0
        self.maxbytes = 0

        self.size_top()

    def start(self):
        self.progress["value"] = 0
        self.maxbytes = 100000
        self.progress["maximum"] = 100000
        self.read_bytes()

    def read_bytes(self):
        self.bytes += 100
        self.progress["value"] = self.bytes
        if self.bytes < self.maxbytes:
            # read more bytes after 100 ms
            self.after(100, self.read_bytes)

    def size_top(self):
        self.resizable(width=False, height=False)

        ws = self.winfo_screenwidth()
        hs = self.winfo_screenheight()

        w = 200
        h = 22

        x = (ws/2) - (w/2)
        y = (hs/2) - (h/2)

        self.geometry('%dx%d+%d+%d' % (w, h, x, y))

        self.protocol("WM_DELETE_WINDOW", self.iconify)
        self.lift()
        self.attributes('-topmost', 'true')
        self.overrideredirect(True)

我的主要代码提取7-Zip文件:

archive_name = 'files.7z'
maps_dir = 'output'

extract = subprocess.Popen('"C:\\Program Files\\7-Zip\\7z.exe" x ' + archive_name + ' -o' + maps_dir, stdout=subprocess.PIPE)

for line in iter(extract.stdout.readline,''):
    print(line.rstrip())

print('Finished')

我需要能够运行我的进度条FinishSetup().start(),同时提取我的7-Zip文件,在完成之后,关闭我的电脑。

我一直试图让这一整天都正确,但我却意识到这可能是不可能的。

请让我知道你的想法,如果还有其他什么我应该尝试。

1 个答案:

答案 0 :(得分:0)

解决方案是在单独的线程或进程中进行提取。该第二个线程或进程可以通过队列与GUI进行通信。您可以使用after在GUI端轮询队列,以便不断重新安排一个每隔几百毫秒检查一次队列的函数。