我正在寻找一个很好的解释,说明在图形应用程序中使用多线程的必要性。在下面的示例中使用了 Python,但问题不是 Python 特定的,它可能适用于任何语言的图形编程的一般设计。
让我们举一个简单的例子。让我们假设有一个应用程序对一组文件执行某种耗时的操作,并将它的进度输出到控制台。让我们假设这个操作每个文件需要 2 秒,并且有 10 个文件需要处理,分别称为 1.txt、2.txt、3.txt、... 10.txt。然后一个示例实现可能如下所示:
安慰
import time
def process(file):
print 'processing {0}...'.format(file)
time.sleep(2.0) #simulate slow operation
files = ['{0}.txt'.format(i) for i in range(1, 11)]
map(process, files)
控制台示例当然是单线程的,并且可以很好地完成工作。现在,如果我们想添加图形进度条,单线程实现可能如下所示:
单线程图形界面
import time, gtk, gobject
def process(file):
print 'processing {0}...'.format(file)
time.sleep(2.0)
class MainWindow(gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.progress = gtk.ProgressBar()
self.progress.set_fraction(0)
self.add(self.progress)
self.connect("destroy", gtk.main_quit)
self.show_all()
files = ['{0}.txt'.format(i) for i in range(1, 11)]
gobject.timeout_add(100, self.submit, files, 0)
def submit(self, files, i):
process(files[i])
self.progress.set_fraction((i + 1.0)/len(files))
if i + 1 < len(files):
gobject.idle_add(self.submit, files, i + 1)
win = MainWindow()
gtk.main()
这似乎工作正常,但是当您运行应用程序时,如果您尝试与应用程序交互(例如尝试调整窗口大小),它将卡住,并且只有在被释放以处理挂起的 gui 事件时每两秒响应一次。最后一个示例是多线程实现,并在整个执行过程中保持响应。
多线程图形用户界面
import time, gtk, gobject, threading
def process(file):
print 'processing {0}...'.format(file)
time.sleep(2.0)
class MainWindow(gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.progress = gtk.ProgressBar()
self.progress.set_fraction(0)
self.add(self.progress)
self.connect("destroy", gtk.main_quit)
self.show_all()
files = ['{0}.txt'.format(i) for i in range(1, 11)]
threading.Thread(target=self.submit, args=(files,)).start()
def submit(self, files):
for i, file in enumerate(files):
process(file)
gobject.idle_add(self.progress.set_fraction, (i + 1.0)/len(files))
if not self.get_visible():
return
gtk.gdk.threads_init()
win = MainWindow()
gtk.main()
对我来说,如果你的代码中有一个长时间运行的阻塞操作,并且你想要一个响应式的 gui,你必须使用多线程解决方案,这对我来说似乎非常清楚和合乎逻辑。没有其他方法可以解决它。是这样吗?我曾多次尝试向其他开发人员解释这一点,但许多人不理解或不同意。有人可以提供对这个概念的解释,关于它的文章的链接,或者如果我的理解不正确,请纠正我。