简体   繁体   中英

Python thread seems to stop/freeze/hang for no apparent reason? Possible causes?

It seems to me that a thread abruptly stops executing without any reason and is never revived or restarted again. What could be possible causes for such behavior? No exception is thrown. At least no exception is detected or printed. It just stops without any information. My pygtk GUI and everything else continues running without problems.

It is limited to a piece of code, but it happens anywhere within that piece. Following code runs inside of that thread. I inserted a lot of prints into my code because I can't debug it. Debugger freezes as well. And running without debugger doesn't change it (so it's not some side effect from debugging)

count = 0
while True: 
            count = count + 1
            #read results calculated by another thread. Done via Queue.Queue
            pos, phrase, site, extractor, infoextractor, image = self.htmlqueue.get(True)
            print "\"", threading.currentThread(), "\"", site, image["link"], infoextractor.__class__.__name__ , FileDownloader.nbdownloads, count
            print "1"
            #if Nones are found in the queue it means that there will be no more data
            if pos is None and phrase is None and site is None and extractor is None and infoextractor is None and image is None: break
            print "2"
            if printstuff: print "preDownloadAll1", image["link"],
            print "3"
            try:
                info = infoextractor.extractValues()
                print info
            except (object) as e:
                print "exception!"

            print "5"    
            if info is None: 
                print "_5.1_"
                continue
            print "6"
            if len(info) == 0: 
                print "_6.1_"
                continue
            print "7"

            if "google" in site:
                print "8"
                adr = image["smallthumb"]
                filename = ImageManager.extractFileFromURL(image["smallthumb"])
            elif info.has_key("thumb"):
                print "9"
                adr = info["thumb"]
                filename = ImageManager.extractFileFromURL(info["thumb"])
            else:
                print "10"
                adr = image["thumb"]
                filename = ImageManager.extractFileFromURL(image["thumb"])
            print "11" 
            localfile = self.imagelocations[site] + "/" + filename
            print "12"
            t = None
            if (not os.path.isfile(localfile)) and predownloadjpegs:
                print "13"
                t = FileDownloader.downloadFileNewThread(url = adr, localtargetdir = self.imagelocations[site], timetofinish = 100)
            print "14"
            tds.append((t, pos, phrase, site, extractor, infoextractor, image, info, adr, localfile))
            print "15"
            if count%100 == 0: print count, "\n"
            print "16"
#            seen[image["link"]] = True
        print "17"

The code runs for about 3000-5000 counts on average and stops at different queue entry (most of the html is cached ;) ). The last output before hanging is random (each time I restart my application it's different). Most of the time it's 3, sometimes 16. number 17 is never reached. I also had a 7. Another time it printed info but it didn't print 5 any more. Yet another time it printed half of the info string.

Since it's 3 most of the time, I suspected an exception there and maybe some very strange delayed detection. But no! print "exception!" was never executed during my tests.

My thread remains in memory after freezing and it's not that blocking

self.htmlqueue.get(True)

Because if I do

pos, phrase, site, extractor, infoextractor, image = None, None, None, None, None, None
                success = False
                while not success:
                    try:
                        pos, phrase, site, extractor, infoextractor, image = self.htmlqueue.get(True,10)
                        success = True
                    except:
                        print "no success", count
                        success = False

then the freezing continues and in most runs there is no "no success"-outputs at all. Even worse, I use a semaphore to run that code section one at a time so all other threads are blocked and waiting for this one thread to finish.

Main GUI thread continues running without disturbance. All threads which are my own are supposed to die after execution (I deamonized them with mythread.setDaemon(True) ). My python version is 2.7.3

I was also thinking about the possibility of an output buffer that would make it only appear random (in reality it would always be the same place, but some output could still be hanging around in output buffer) But since every print introduces a new line, I would guess that each output is flushed immediately, so I don't miss any output at the point where thread freezes. My development environment is eclipse with pydev.

FileDownloader.downloadFileNewThread starts yet another thread from inside of that thread. Could that be a problem as well? threads starting other threads? It also seems to make no difference if I don't demonize vs. if I do.

It really looks to me that the code randomly freezes. But why and how could that be???

OK guys, after 3 days of banging my head against the wall I think I solved it. At least nothing hangs any more.

Pygtk seems to be the reason http://faq.pygtk.org/index.py?file=faq20.006.htp&req=show

Pygtk is able to block long running threads forever. It acquires the GIL lock and doesn't let go. The thread simply hangs in memory but is not being executed any further.

All I had to do was to call

gobject.threads_init()

before anything else gtk related. In other words, my code starts like this

import gtk
import gobject
import MainGUI

if __name__ == "__main__":
    gobject.threads_init()
    from MainGUI import MainGUI
    MainGUI.instance = MainGUI()
    gtk.main()

Luckily I strictly separate my logic from GUI and never instantiate any gtk Elements inside of my own threads. So that's the only line I really needed. If someone still needs to be able to handle GUI objects in own threads, he has to use

gobject.idle_add(callback_function, args)

Another lesson I learned is that Queues can have a quite limited memory capacity and they can also lead to blocking behaviour if they get stuffed too much.

Theads starting yet another thread shouldn't be any problem since as far as I understand by now, those threads are all started "at the same level" and python doesn't know or maintain any hierachy between them. It's just the pseudo random fight over the GIL (Global Interpreter Lock) that pygtk screws up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM