簡體   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