1

Even when run in a seperate thread my UI hangs while a large file is being loaded into a Text widget. Is it just because the application is under heavy load or is there a way I can keep the UI functional while this is happening. Im loading several text files in different widgets so the hang up is longer than desired.

from tkinter import *
import threading

i = 'large/text/file/400,000+lines'
root = Tk()

txt = Text(root)
txt.grid()


def loadfile():
    with open(i, 'r') as f:
        a = f.readlines()
        txt.insert('end', ' '.join(a))
        #for line in a:
         #   txt.insert('end', line)

def threadstarter():
    startit = threading.Thread(target=loadfile())
    startit.start()

btn = Button(root, text= 'start', command=lambda: threadstarter())
btn.grid()

root.mainloop()

Tested on several machines with plenty of resources.

sidnical
  • 421
  • 1
  • 6
  • 23
  • What you call a 'separate thread' isn't actually so _separate_ because of the Python's GIL which allows you to run _only one Python thread at once_. – ForceBru Apr 21 '17 at 17:10
  • 1
    How large is large? Also, you're not running the code in a thread. `target=loadfile()` will immediately run `loadfile()` and give the results to the `target` attribute. – Bryan Oakley Apr 21 '17 at 17:11
  • @BryanOakley File size is ~50mb and text file has ~400,000 lines. – sidnical Apr 21 '17 at 17:14
  • @BryanOakley am I using threading wrong? Maybe thats the problem. – sidnical Apr 21 '17 at 17:15
  • I am able to read about 100,000 lines / 100mb in under a second. – Bryan Oakley Apr 21 '17 at 17:16
  • You shouldn't be using threading at all. Tkinter doesn't work well with threads. – Bryan Oakley Apr 21 '17 at 17:16
  • @ForceBru I've read about this. Any way around it? I've played with multiprocessing a little but ran into problems getting it to work right. – sidnical Apr 21 '17 at 17:16
  • Why do you think you need threading or multiprocessing? And no, there's no way around it. See http://stackoverflow.com/a/38767665/7432 – Bryan Oakley Apr 21 '17 at 17:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142307/discussion-between-sidnical-and-bryan-oakley). – sidnical Apr 21 '17 at 17:17
  • @sidnical, as far as I know, only a C extension can give you true multithreading, but Python's `multiprocessing` allows you to run code in multiple Python interpreters as if they were threads. – ForceBru Apr 21 '17 at 17:19
  • @BryanOakley to keep the UI running smoothly while parsing happens in the background. Its been working fine for me until I started dumping the entire file into a widget instead of parsing it line by line which takes a long time. – sidnical Apr 21 '17 at 17:20
  • Your question mentions nothing about parsing. You asked about it hanging when inserting 50mb, and that can't be reproduced with the code you provided, because reading 50 mb and inserting into a text widget takes under a second. – Bryan Oakley Apr 21 '17 at 17:27
  • @ForceBru: tkinter widgets can't span a process boundary. – Bryan Oakley Apr 21 '17 at 17:28

2 Answers2

1

What Bryan is saying is that you need to launch a thread like this:

from tkinter import *
import threading

i = 'large/text/file/400,000+lines'
root = Tk()

txt = Text(root)
txt.grid()

def loadfile():
    with open(i, 'r') as f:
        txt.insert('end', f.read())

def threadstarter():
    startit = threading.Thread(target=loadfile)
    startit.start()

btn = Button(root, text= 'start', command=threadstarter)
btn.grid()

root.mainloop()
Novel
  • 13,406
  • 2
  • 25
  • 41
1

In order to invoke loadfile in a separate thread with positional/keyword arguments, use the args and kwargs arguments to threading.Thread like so:

def threadstarter():
    startit = threading.Thread(target=loadfile, args=(42,), kwargs={'a': 'foo'})
    startit.start()

... which would invoke loadfile(42, a='foo') in the thread.

Mathias Rav
  • 2,808
  • 14
  • 24