Python Forum
Python Tkinter Simple Multithreading Question
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python Tkinter Simple Multithreading Question
#1
I have a simple Listbox with a list of names that I would like to print concurrently, but also in the order of which they were added to the Listbox (alphabetically in this case). I'm just using this example to practice creating multiple threads to handle each name in the listbox.

So, just to clarify, I'd like to have 1 thread for each name in the list to print each name. I prefer to do this in the order they are in queue from whatever the listbox has in it.

Here's what I've tried thus far:

from tkinter import Tk, Button, Listbox
import threading

class MainWindow(Tk):
  def __init__(self):
    super().__init__()

    self.lb1 = Listbox(self, width=26, cursor='hand2')
    self.lb1.pack(side='left', fill='y', padx=20, pady=20)

    self.b1 = Button(self, text='START', bg='green', fg='white', cursor='hand2', command=self.start_thread)
    self.b1.pack(side='left')

    self.lb1.insert('end', 'Aaron')
    self.lb1.insert('end', 'Billy')
    self.lb1.insert('end', 'Chris')
    self.lb1.insert('end', 'David')
    self.lb1.insert('end', 'Edward')
    self.lb1.insert('end', 'Frank')
    self.lb1.insert('end', 'George')
    self.lb1.insert('end', 'Howard')
    self.lb1.insert('end', 'Ian')
    self.lb1.insert('end', 'Johnny')

def start_thread(self):
    for i in range(self.lb1.size()):
        t1 = threading.Thread(target = self.work, args=(i,))
        t1.start()



def work(self, i):
    print(self.lb1.get(i))



if __name__ == '__main__':
    app = MainWindow()
    app.title('Main Window')
    app.configure(bg='#333333')

    app.mainloop()
The problem that I'm having is that the threads do not fire off properly. They print the names out in random order and also on the same exact line as if they are just one name at times. How do I get better control of each thread that will print each name concurrently?

Below is an example of what is being printed out:


ChrisEdward
DavidBilly

George

Aaron
Frank
Ian
JohnnyHoward
Reply
#2
If you want to control when they run, don't put each in their own thread? Unless the code something to synchronize execution of the threads, they just finish in whatever order they want. Normally you don't care.

As for them all printing on the same line, I am not seeing that, but it is probably just because stdout is not being flushed after each write
Reply
#3
There are multiple threads each trying to control the same resource, terminal output, so the results are unpredictable. I use multiprocessing and a Manager (common) list in the cases when I want to do something like this. But while memory is faster than printing, the order can not be guaranteed and so you would sort the list before printing.

from tkinter import Tk, Button, Listbox
from functools import partial
import multiprocessing as mp
 
class MainWindow():
  def __init__(self, mp_list):
    self.root=Tk()
    self.root.title('Main Window')
    self.root.configure(bg='#333333')
 
    self.lb1 = Listbox(self.root, width=26, cursor='hand2')
    self.lb1.pack(side='left', fill='y', padx=20, pady=20)
 
    self.b1 = Button(self.root, text='START', bg='green', 
              fg='white', cursor='hand2',
               command=partial(self.start_thread, mp_list))
    self.b1.pack(side='left')
 
    Button(self.root, text='QUIT', bg='orange', 
               command=self.root.quit).pack(side="left")

    self.lb1.insert('end', 'Aaron')
    self.lb1.insert('end', 'Billy')
    self.lb1.insert('end', 'Chris')
    self.lb1.insert('end', 'David')
    self.lb1.insert('end', 'Edward')
    self.lb1.insert('end', 'Frank')
    self.lb1.insert('end', 'George')
    self.lb1.insert('end', 'Howard')
    self.lb1.insert('end', 'Ian')
    self.lb1.insert('end', 'Johnny')
 
    self.root.mainloop()

  def start_thread(self, mp_list):
        self.b1.config(state="disabled")
        self.process_list=[]
        for i in range(self.lb1.size()):
            t1 = mp.Process(target = self.work, args=(i, mp_list,))
            t1.start()
            self.process_list.append(t1)

  def work(self, i, mp_list):
        mp_list.append(self.lb1.get(i))
 
 
 
if __name__ == '__main__':
    manager=mp.Manager()
    mp_list=manager.list()
    app = MainWindow(mp_list)
 
    print(mp_list) 
Reply
#4
C:\Users\Aaron\AppData\Local\Programs\Python\Python310\python.exe "C:/Users/Aaron/Documents/Python/EBSEO PRO/2.py"
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:\Users\Aaron\Documents\Python\EBSEO PRO\2.py", line 41, in start_thread
    t1.start()
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\context.py", line 336, in _Popen
    return Popen(process_obj)
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_tkinter.tkapp' object
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Users\Aaron\AppData\Local\Programs\Python\Python310\lib\multiprocessing\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
EOFError: Ran out of input
(Dec-14-2022, 08:03 PM)woooee Wrote: There are multiple threads each trying to control the same resource, terminal output, so the results are unpredictable. I use multiprocessing and a Manager (common) list in the cases when I want to do something like this. But while memory is faster than printing, the order can not be guaranteed and so you would sort the list before printing.

from tkinter import Tk, Button, Listbox
from functools import partial
import multiprocessing as mp
 
class MainWindow():
  def __init__(self, mp_list):
    self.root=Tk()
    self.root.title('Main Window')
    self.root.configure(bg='#333333')
 
    self.lb1 = Listbox(self.root, width=26, cursor='hand2')
    self.lb1.pack(side='left', fill='y', padx=20, pady=20)
 
    self.b1 = Button(self.root, text='START', bg='green', 
              fg='white', cursor='hand2',
               command=partial(self.start_thread, mp_list))
    self.b1.pack(side='left')
 
    Button(self.root, text='QUIT', bg='orange', 
               command=self.root.quit).pack(side="left")

    self.lb1.insert('end', 'Aaron')
    self.lb1.insert('end', 'Billy')
    self.lb1.insert('end', 'Chris')
    self.lb1.insert('end', 'David')
    self.lb1.insert('end', 'Edward')
    self.lb1.insert('end', 'Frank')
    self.lb1.insert('end', 'George')
    self.lb1.insert('end', 'Howard')
    self.lb1.insert('end', 'Ian')
    self.lb1.insert('end', 'Johnny')
 
    self.root.mainloop()

  def start_thread(self, mp_list):
        self.b1.config(state="disabled")
        self.process_list=[]
        for i in range(self.lb1.size()):
            t1 = mp.Process(target = self.work, args=(i, mp_list,))
            t1.start()
            self.process_list.append(t1)

  def work(self, i, mp_list):
        mp_list.append(self.lb1.get(i))
 
 
 
if __name__ == '__main__':
    manager=mp.Manager()
    mp_list=manager.list()
    app = MainWindow(mp_list)
 
    print(mp_list) 
Reply
#5
Ran fine on my Linux box. Don't have any idea what this means

EOFError: Ran out of input
Reply
#6
It is a pickling error. You don't get it running on linux because linux python doesn't pickle arguments passed to processes.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Very Beginner question on simple variables Harvy 1 188 Apr-12-2024, 12:03 AM
Last Post: deanhystad
  Simple Question - ' defined as "a". ?' Ryan012 10 1,639 May-27-2023, 06:03 PM
Last Post: Ryan012
  Very simple question about filenames and backslashes! garynewport 4 1,963 Jan-17-2023, 05:02 AM
Last Post: deanhystad
  Tkinter Web Scraping w/Multithreading Question.... AaronCatolico1 3 1,256 Dec-16-2022, 11:34 AM
Last Post: deanhystad
  python Multithreading on single file mg24 3 1,749 Nov-05-2022, 01:33 PM
Last Post: snippsat
  multithreading Hanyx 4 1,336 Jul-29-2022, 07:28 AM
Last Post: Larz60+
  A simple "If...Else" question from a beginner Serena2022 6 1,731 Jul-11-2022, 05:59 AM
Last Post: Serena2022
Question Problems with variables in multithreading Wombaz 2 1,338 Mar-08-2022, 03:32 PM
Last Post: Wombaz
  Simple arithmetic question ebolisa 5 2,071 Dec-15-2021, 04:56 PM
Last Post: deanhystad
  Simple code question about lambda and tuples JasPyt 7 3,337 Oct-04-2021, 05:18 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020