Explain the need for multi-threaded GUI programming

I am looking for a good explanation of the need for multithreading in graphical applications. The examples below use Python, but the question is not specific to python, it is applicable, perhaps, to the general design of graphic programming in any language.

Let's look at a simple example. Suppose there is an application that takes some time to work on a collection of files and displays it on the console. Suppose 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 might look like this:

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, of course, is single-threaded and works great. Now, if we want to add a graphical progress bar, a single-threaded implementation might look like this:

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 works fine, but when you start the application, if you are trying to interact with the application, for example, try resizing the window, for example, it will get stuck and will only respond every two seconds when it is released before processing pending gui events. The ultimate example is multi-threaded implementation and remains flexible at runtime.

multithreaded 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-term locking operation in your code and you want the flexible gui to use a multi-threaded solution. There is no other way. This is true? I tried to explain this many times to other developers, but many do not understand or disagree. Can someone give an explanation of this concept, a link to an article on it, or correct me if my understanding is incorrect.

+7
source share
3 answers

Your understanding is correct. If the application does not work with muli-threaded, the application expects completion of each operation. When your application is multithreaded, you use one thread to handle GUI actions and another to process files.

I have no article or link to anything like that. Maybe this helps if you think of flows as people, everyone has their own work, and everyone can only do one thing at a time.

+4
source

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

This main loop calls all the event handlers and other functions that you provide. Now, if one of these functions takes too much time (for example,> 100 ms), then there will be a very noticeable effect on the responsiveness of the user interface, since the main loop will not be able to process more events.

This section should be discussed in detail in the “advanced concepts” section of any book on GUI programming, regardless of the programming language of the toolkit used.

+2
source

Multithreading is one way to get closer to this, but not necessarily the only (or best) way. As an example, python greenlets provide a way to run concurrent processes on a single thread, avoiding the locking problems associated with multi-threaded. I would, of course, consider that green bars are the preferred solution in most cases, simply because of the relative simplicity of their coding.

0
source

All Articles