繁体   English   中英

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

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

在我看来,线程突然停止执行而没有任何原因,并且永远不会恢复或重新启动。 这种行为可能是什么原因造成的? 没有异常被抛出。 至少没有检测到或打印异常。 它只是停止而没有任何信息。 我的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)它们取消妖化了)。 我的python版本是2.7.3

我也在考虑是否有可能使输出缓冲区只是随机出现的缓冲区(实际上,缓冲区总是在同一位置,但是某些输出仍会在输出缓冲区中徘徊),但是由于每张印刷品都会引入新的一行,我想每个输出都会立即刷新,因此在线程冻结时我不会错过任何输出。 我的开发环境因pydev而黯然失色。

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

在我看来,代码随机冻结了。 但是,为什么以及怎么可能呢?

好的,伙计们,我把头撞在墙上三天后,我想我解决了。 至少没有任何东西可以挂了。

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启动另一个线程应该没问题,因为据我所知,这些线程都是“在同一级别上”启动的,而python不知道或保持它们之间的任何层次。 pygtk只是对GIL(全局解释器锁定)的伪随机竞争而已。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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