Python线程似乎停止/冻结/挂起没有明显的原因?可能的原因?

时间:2014-09-08 18:50:02

标签: python multithreading block freeze hang

在我看来,一个线程突然停止执行没有任何理由,并且永远不会复活或重新启动。这种行为可能导致什么?没有异常被抛出。至少没有检测到或打印出异常。它没有任何信息就停止了。我的pygtk GUI和其他一切继续运行没有问题。

它仅限于一段代码,但它发生在该部分的任何地方。以下代码在该线程内部运行。我在代码中插入了很多打印件,因为我无法对其进行调试。调试器也冻结了。在没有调试器的情况下运行并没有改变它(因此调试没有副作用)

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"

代码平均运行大约3000-5000个计数,并在不同的队列条目处停止(大多数html被缓存;))。挂起之前的最后一次输出是随机的(每次重新启动我的应用程序时它都不同)。大部分时间它是3,有时是16.数字17从未到达。我还有一个7.另一次它打印信息,但它不再打印5。还有一次,它打印了一半的信息字符串。

由于它大部分时间都是3,我怀疑有一个例外,可能还有一些非常奇怪的延迟检测。但不是!打印"例外!"我的测试期间从未执行过。

我的帖子在冻结后仍留在内存中,而且不是阻止

self.htmlqueue.get(True)

因为如果我这样做

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

然后冻结继续,并且在大多数运行中没有"没有成功" - 输出。 更糟糕的是,我使用信号量一次运行一个代码段,以便阻止所有其他线程并等待这一个线程完成。

主GUI线程继续运行而不受干扰。我自己的所有线程都应该在执行后死掉(我用mythread.setDaemon(True)对它们进行了deamonized)。我的python版本是2.7.3

我还在考虑输出缓冲区的可能性,它只会使它看起来是随机的(实际上它总是在同一个地方,但是某些输出仍然可以在输出缓冲区中徘徊)但是因为每个打印都引入了新行,我猜每个输出都会立即刷新,所以我不会错过线程冻结的任何输出。我的开发环境与pydev有关。

FileDownloader.downloadFileNewThread从该线程内部启动另一个线程。这也可能是一个问题吗?线程启动其他线程?如果我没有妖魔化,那么它似乎没有任何区别。

我真的觉得代码随机冻结了。但是为什么以及怎么可能是???

1 个答案:

答案 0 :(得分:4)

好的伙计们,经过3天的撞击我的头撞墙后,我想我已经解决了。至少没有什么可以挂起来了。

Pygtk似乎是的原因 http://faq.pygtk.org/index.py?file=faq20.006.htp&req=show

Pygtk能够永久阻止长时间运行的线程。它获得了GIL锁并且没有放手。该线程只是挂在内存中,但没有被执行。

我所要做的就是致电

gobject.threads_init()

之前gtk相关的事情。换句话说,我的代码就像这样开始

import gtk
import gobject
import MainGUI

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

幸运的是,我严格地将我的逻辑与GUI分开,并且永远不会在我自己的线程中实例化任何gtk元素。这是我真正需要的唯一一条线。如果某人仍然需要能够在自己的线程中处理GUI对象,他必须使用

gobject.idle_add(callback_function, args)

我学到的另一个教训是,队列的内存容量非常有限,如果填充太多,它们也会导致阻塞行为。

Theads开始另一个线程不应该是任何问题,因为就我现在所理解的而言,这些线程都是在同一级别开始的#34;"并且python不知道或维护它们之间的任何层次结构。这只是对GIL(全局解释器锁)的伪随机争斗,pygtk搞砸了。