Explanation of need for Multi Threading GUI programming

爷,独闯天下 提交于 2020-12-29 03:57:12

问题


I'm looking for a good explanation of the need to use multi-threading in graphical applications. In the examples below Python is used but the question is not python specific it applies to maybe the general design of graphical programming in any language.

Lets take a simple example. Let's assume there is an application that does some sort of time consuming operation on a collection of files, and that it outputs it's progress to the console. Lets assume that this operation takes 2 seconds per file and that there are 10 files to process called 1.txt, 2.txt,3.txt, ... 10.txt. Then an example implementation could look like the following:

console

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)

The console example is of course single threaded and does the job just fine. Now if we wanted to add a graphical progress bar a single threaded implementation might look like the following:

single-threaded gui

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()

This seems to work fine, but as you run the application if you try and interact with the application like try and resize the window for example it will get stuck and only respond every two seconds when it gets freed up to process pending gui events. The final example is a multi-threaded implementation and stays responsive throughout execution.

multi-threaded 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()

It seems perfectly clear and logical to me that if you have a long-running blocking operation in your code and you want a responsive gui that you have to use a multi-threaded solution. There is no other way around it. Is this the case? I have tried to explain this many times to fellow developers but many don't understand or don't agree. Can someone provide an explanation of this concept, a link to an article on it, or correct me if my understanding is incorrect.


回答1:


Your understanding is correct. If an application isn't muli-threaded the application waits for every operation to finish. When your application is multi-threaded you use one thread to handle GUI actions and another to process the files.

I don't have an article or a reference to something similar. Maybe it helps if you think of threads as people, each has it's own job and each can only do one thing at a time.




回答2:


The main reason is, that GUI toolkit process all events (mouse movement, button click, keyboard input, system events, etc) in the mainloop, which is not part of the code you write for you GUI application.

This main loop call all the event handlers and other functions you provide. Now, if one of those functions take too long (e.g. > 100ms), then there will be a very noticeable effect on UI responsiveness, as the main loop will not be able to process more events.

This topic should be discussed in details in the "advanced concepts" section of any book on GUI programming, regardless of programming language of toolkit used.




回答3:


Multithreading is one way of approaching this, but not necessarily the only (or best) way. As a python example, greenlets provide a way of running concurrent processes within the same thread, avoiding the problems with locking associated with multithreading. I would certainly consider greenlets to be a preferred solution in most cases simply because of the relative ease of coding them.



来源:https://stackoverflow.com/questions/13343096/explanation-of-need-for-multi-threading-gui-programming

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!