看板 Python 關於我們 聯絡資訊
今天改的版本,突然間陷入 while loop 無法中止 強迫中止時錯誤訊息是 File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ threading.py", line 1388, in _shutdown lock.acquire() 這種訊息有和沒有差不多 有 lock 沒有釋放? 於是我寫了個 MyLock 取代 threading.Lock 開始記錄到底是哪個 Lock 有進入而沒有退出 全都有退出!根本查不到 最後是透過 git 不斷捲回舊版,找到十二小時前的版本還可以正常退出程式 一查,重點不在程式,在資料! 某一種資料格式,我會啟動 Timer, 而 Timer 時間到後,我會再重啟 Timer (其實就是連續脈衝波,每隔幾秒一次的意思) 因為我預約了下一次的執行需求,所以程式無法釋放 只要 cancel timer, 就解掉這個 bug 了 (bug 是一直存在的,只是一直沒鍵入這種資料凸顯 bug) 還真是忘了,在 Python 的 Timer 是以 Thread 來實現 而骨子裡可能設了個 lock 那我問題來了:這次是幸運在 git 裡保存夠多細節,且能捲回一定能釋放的舊版 假設沒這樣的環境,只能靠我自己抓,而錯誤訊息又只說有 lock 沒釋放 我能回溯知道是哪一行程式產生的 lock 鎖住了嗎? 有什麼參數,什麼 debug tool 能用嗎? 謝謝 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 116.241.233.114 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Python/M.1680299059.A.BEA.html
robert09080: Rlock 試試? 04/01 11:21
RLock 是允許重複進入,避免同一個 thread 自己把自己卡住 而我的要求是回應卡住的物件是在哪行指令生成 舉例來說 Line 10: a = new C1() # test.c 這是產生物件;目前都有自動釋放,但假如在沒自動釋放的 C 語言 而且我沒有釋放物件,造成記憶體浪費, 有工具能回應我,浪費的記憶體在 test.c/Line 10 嗎? 我還真用過這種工具
lycantrope: gdb 04/01 12:27
哇!我試試! 謝謝 ... 超過我的程度 XD 裝了,跑不起來.. ※ 編輯: HuangJC (116.241.233.114 臺灣), 04/01/2023 15:21:44
b0920075: c/c++ 的話有 sanitizer valgrind 之類的工具可以看 04/02 17:33
poototo: 有考慮...print嗎?cc 04/03 20:03
lycantrope: cc 04/03 20:16
leolarrel: 我猜二樓其實是要說pdb?? 04/05 17:35
當年我用過 debug tool 抓記憶體漏洞之類,真的過癮 但有種很怪的感覺,那是高手在替我做事,而且能力是有限的 比如找尋未釋放記憶體的原理是什麼? a = new C1() // 配發記憶體 a del a // 釋回 a 如果 a 忘記釋放,要怎麼找出 a 在哪一行配發的? 畢竟 a 這個符號可能被重覆配發,也可能 b = a // 被 b 承接走 a = NULL // 棄用 a 這個符號,但 b 忘了釋放 XD 因此這種 tool 能做的只有。。當初 a 配發時,就把 debug info 順便存入 比如覆寫 new 這功能,成為 DEBUG_NEW 然後隱性的傳入程式的資訊(利用 __FILE__, __LINE__ 這種 compiler 維護的符號) 這也代表配發記憶體時,我本來只配幾個 byte, 但可能同時配發更多的 debug byte 因此 debug 時的速度會變慢,耗用記憶體會增加 但高手替我抓還是很好用 XD 等我程式寫太大時,這種 tool 因為要多耗用很多 debug 資源,就會跑不動 最佳方案仍然是自己寫 debug tool 但我如果功力高到會寫 debug tool,我當初就不會犯錯了! 先有雞還是先有蛋的問題 -------- 總之我這次學到了,Timer 元件其實要注意它的配發和釋放 ※ 編輯: HuangJC (123.204.157.162 臺灣), 04/06/2023 01:08:28
andy19960407: 為什麼一般感覺不太會遇到這種問題,你的需求是特 04/06 23:27
andy19960407: 別刁鑽還是你的寫法有可以再優化的地方? 04/06 23:27
是遇到了才知道遇到了啊.. 我一開始可超級謹慎的 class MyApp(App): def f1(self): self.destroy() app = MyApp() pApp = weakref.proxy(app) btn = PushButton(app, command=pApp.f1) app.display() 比如我曾這樣寫程式,其中 pApp 根本沒必要 為什麼這樣寫?因為我怕 btn 物件裡如果保有 app 因為參考到自己,會導致永不釋放 所以凡參考我都只留 weak 版本 後來我發現不這麼寫,照樣不會卡,照樣釋放,想法可以很單純 XD 我從完全沒有 gc 的 C 語言學起的,從前記憶體管理都自己來 那時如果釋放了不把變數標成 null, 再叫用到就 null access 能碰到的問題可非常多 a = new C1(); b = a; // 比如進入函式,也是拷走一個 a 指標在函式裡用 del b; // 除非我不在函式裡釋放物件,否則當然會寫這種東西 a.xxx // 這時外面還想取用 a pointer 就慘了,null access 後來開始用有 gc 的語言,可是參照次數很重要 如果還有任何指標參照到物件,物件就不會釋放 那循環參照怎麼算?還真是測了才知道 一般不會遇到?不是,我一開始學時曾經有遇到,但不知道就寫了兩年 舉例來說,樹莓派一開機就跑我的程式,但從沒想過要關機 執行完畢直接斷電,就算程式無法釋放,都斷電了是有何差別? 只有刻意去想,我就是要讓程式釋放,才會測試到這件事 比如我可能要寫遠端更新,要讓程式結束並且重開機 喔,還是有很暴力的寫法,比如下個 kill process 指令 在程式未能退出的情況下,由 os 端殺掉 XD 會去注意是潔癖吧.. 總覺得,類似檔案沒有 close 等循序退出問題,如果沒做,很不舒服 別人沒遇到嗎? 比如我在寫 ios 手機時,用的是 obj c 我也下載過別人的函式庫用 我看別人防這個也防得很嚴 一堆 weaf ref 在用 應該說,為什麼 python 在參照到自己的指標留著時還能釋放 這才是超乎我預期的 XD 所以 Timer 在幾秒後才要啟動,而它啟動時要用到的指標要不要 weak 版? 程式想退出了,幾秒後根本就不存在,若保留指標程式就無法退出 那按鍵按了要退出程式,按鍵的程式裡保留指標,為什麼可以退出 :P 那也是測了才知道。。 QA 不會做這項測試,都專注在跑程式,而不是退出程式 XD 我也是哪天心血來潮才測到的。 那時曾經呼叫同事寫的副程式,用 try-catch 包起來呼叫 甚至是每次呼叫前才 load library (本來可以用靜態寫的,不必這麼麻煩) 呼叫後就 free library 為什麼要這樣做?因為同事記憶體釋放沒寫好啊,我整個 free 掉才會乾淨 所以一般是沒遇到,還是沒注意到? ※ 編輯: HuangJC (123.204.157.162 臺灣), 04/07/2023 01:00:44 甚至我想過一個問題:參照到自己,或說交互參照 這種還有法子釋放資源是怎麼做的? (同事是說有很多論文,不過我不擅長查) 如果說這機制有 bug 會不會我剛用沒問題,但用多了,資源就變無法釋放? 那這不是我有問題,是寫釋放的有 bug, 沒確實 implement 出來 看過是說 gc 不會時時刻刻,而是久久做一次 所以我以前去主動檢查有沒有釋放,也常沒釋放 必需在主動檢查前,先主動催 gc 做一次垃圾搜集 會不會就是因為這樣,我下載的第三方函式庫才廣用 weak 版本?
Hsins: 這些資訊不夠去找,複現的情境也不夠清楚,能夠複現的話就 04/07 18:10
Hsins: 多埋幾個點去 logging 吧 04/07 18:10
Hsins: 樹莓派那段看不是很懂,你敘述了你的做法,但沒有敘述為什 04/07 18:12
Hsins: 麼要這樣做。這也是為什麼前面會說一般不會遇到,他想了解 04/07 18:12
Hsins: 的是你的「需求」跟你現在的「問題」之間是不是存在 X-Y 問 04/07 18:12
Hsins: 題 04/07 18:12
leolarrel: Hsins,建議你可以a他id參考一下 04/07 18:28
a 我 id 其實沒幫助 我直說好了,有人說我半桶水 那我能怎樣?膨風說自己全都懂? 前不久和另一位也是資深工程師聊這邊的狀況 聊到有人叫我去讀 os,他直接回我,他也從業幾十年,但從沒讀過 os 所以我們只能這麼說:底線就是,這本來就是我的責任 資訊不夠,多少是因為我不能把公司產品全丟到網路上,source code 公開 所以得用各種抽象的方式,只曝露一些點來討論 若實在是不行也就算了
Hsins: ~ " ~ 不是很能讀懂問題... 04/07 19:42
Sunal: 建議問問題可以把完整脈絡寫出來(包含範例、使用情境、需求 04/08 09:54
Sunal: ),而不是大量的類似內心os的口語文字。簡單說就是文字要 04/08 09:54
Sunal: 精煉一點 04/08 09:54
Sunal: 另外,寫python其實不需刻意del變數的,用不到gc自然就收 04/08 09:57
Sunal: 走了(simple is better) 04/08 09:57
這我知道,知道還這麼做,就代表混入 debug 等心得.. 當年寫 c,寫到某個地方,我說懷疑 compiler 有 bug 也是被人狠狠嘲笑 幾年後看到臉書上另一個朋友說,c compiler 有一大堆 bug... 咦,原來也有別人遇到,那我被笑又怎麼回事;只能說有沒有人同樣見識到了 責任不能推到 compiler 去,但我們得去驗證這些問題存不存在 所以對這些都是有限信任 obj c 也是有 gc 的 (應該說隨著年代, 很多語言的特性互相學習) 而它若是自我參照時,就不會釋放! 這我能寫一個極小的程式驗證到 發生時,就要'打破這個環節' 在 obj c 我也不會去 del, 我是把指標設為 None 這樣循環參照就打破了 (我這篇裡用到 del, 但那是 c 啊,先還原到最原始,沒有 gc 的環境描述問題) 去說明這些我知道似乎也沒有意義 知道我也是碰到這些 bug 了
andy19960407: Sunal懂我 哈哈哈 04/08 11:10
Sunal: threading.py", line 1388, in _shutdown 04/08 11:50
Sunal: 光這一行就可以從 python threading.py source code 知道 04/08 11:50
Sunal: class Timer(Thread): 這件事情...(而且文件也有寫) 04/08 11:51
Timer 是一種 Thread 這我知道 我不知道的是我啟動了 lock lock 一般來說,是 multi-thread 時, 某 thread 要求獨佔資源,其它 thread 不能進入 而我使用 Timer 時,我沒要獨佔什麼,所以我沒想到它啟動了 lock 或者,這問題不是 Timer 啟動了 lock 我程式中本來就用了很多 lock, 憑最後出現的錯誤訊息,我並不知是哪個 lock 未釋放 不然改個說法:我能不能把每個 lock 命名 當程式用強迫退出的方式並且收到錯誤訊息 能夠知道是哪個 lock 沒有釋放 ※ 編輯: HuangJC (116.241.233.114 臺灣), 04/08/2023 16:24:15
Sunal: source code 中也有用到 lock 如果你看到錯有去看 code 就 04/08 16:42
Sunal: 知道了 04/08 16:42
Sunal: 另外,你也可以debug時hack python source 去達到你的目的 04/08 16:44
蠻常 hack 的,但還是不行,主要是猜測行為都猜錯了,就無法看著 code 想像 來看這麼短的程式就好 from guizero import App, PushButton app = App() btn = PushButton(app, command=app.destroy) app.display() 這程式的目的只有一個:產生一個按鍵,按了就退出程式 我本來以為這不會正常運作的 理由是 btn 是個物件,它裡面有變數參照了 app.destroy 那這樣 app 的 ref count 不是會加一嗎? 不用執行,光有變數拷走我的指標,就要加一了,沒錯吧.. 不然萬一要執行時 app 不存在怎麼辦? 按下按鍵,我以為程式要卡死不能退出,但它就是順利退出了 我就是以為,這個 gc 可以自行解決啊? 結果 timer 的倒沒自行解決,得由我來 cancel timer! ※ 編輯: HuangJC (116.241.233.114 臺灣), 04/09/2023 13:21:02
Sunal: 感覺你還是沒搞懂,實在幫不了。包含我前面說的「建議」也. 04/09 13:50
lycantrope: 很難救 04/09 14:51
Hsins: 既然都在處理 thread 跟 lock 問題,去把 OS 裡這部分的概 04/09 15:54
Hsins: 念補齊滿合理的…… 04/09 15:54
要講這麼籠統的話,建議計概重學,建議 python 重學,不也都說得通? 成語 邯鄲學步 就這意思了 學著學著有沒有更高明?還是反而被搞糊塗了呢? thread 就我所知,就是系統把目前所有的暫存器通通儲存起來, 然後切換到另一個 thread 的 context 去 之後再切換回來,除了時間點改變之外,CPU 完全可以在這個點繼續往下執行 而兩個 thread 如果有共用變數,且搶著修改,可能混成一團 因此在有必要獨佔一個變數時,就可以用一個同步物件來 lock 使用權 當然隨著應用的方式不同,看起來也許不像鎖著物件,而像鎖著程式區塊 比如 critical section 的應用方式 知道,但解決不了 因為在這個地方忽略而產生 bug, 錯訊訊息不見得是在這個地方 所以我是在請教 debug 技巧 就以我文章最前面所講的問題,我是已經解決了 我是知道解法,再回頭看錯誤訊息,覺得沒有幫助 其實我想要的是在程式強硬退出後,有'列舉所有 thread 狀態'這類指令 所以我已經在打造自己的 debug tool 了 希望可以追蹤 thread 當下的行為,以知道 thread 為何釋放不了 ※ 編輯: HuangJC (49.217.174.143 臺灣), 04/10/2023 01:51:25
leolarrel: 就跟你們說那邊有馬蜂窩了,你們... 04/10 11:31
淌渾水都是自願的,而且都不是簡單的工程 你說馬蜂窩又怎樣呢?
s9041200: 樓上+1 04/10 21:25
s9041200: 如果可以穩定重現又有行數其實蠻幸福的,對準點直接打lo 04/10 21:25
s9041200: g就好。 04/10 21:25
s9041200: 之前寫mit 6.824有deadlock都是這樣找的。 04/10 21:25
Hsins: 我覺得這篇敘述的思考方向很怪……對我來說,應該是試圖找 04/10 22:00
Hsins: 到問題點,而不是去找一個或者是造出一個專門的除錯工具… 04/10 22:01
在針對微軟出的一本比一般磚塊還大的經典書籍,教人 debug 時 就有介紹到自己打造 debug 工具 差別是時代進步後,會有人直接準備好這個工具給你
Hsins: 能夠複現當然是最好,不能夠複現會去找相關日誌,如果日誌 04/10 22:02
Hsins: 不足以判斷,那說明日誌輸出的埋設點不足;以你的例子來說 04/10 22:02
Hsins: ,我不會想著要怎麼在強制退出後列出 thread 狀態這件事, 04/10 22:03
Hsins: 而是紀錄 thread 切換不同狀態,以及他的初始化和結束。 04/10 22:05
埋設本身就是一堆 code,如果這種 code 重覆用,就值得打造一個工具 所以你其實不能反駁我的做法 最單純的 log, 類似 echo abc >> myApp.log 但複雜的也是 import logging,有人打造好了不是? 以分配記憶體的 new 指令來說 a = new C1(); 改成 a= DEBUG_NEW c1(); 這樣的思維邏輯,不是我想出來的,是經典書籍上有的 你可以說現在時代進步,這招太舊 但這招真的不是我想的。
Hsins: 另外,你是不是曲解邯鄲學步的意思了?建議回去補足作業系 04/10 22:07
Hsins: 統知識,我認為有其必要性;至於學習的好不好,那是學習者 04/10 22:09
Hsins: 策略跟方向上可能有錯誤,不代表這個建議是錯誤的呀。  04/10 22:10
那我也只能說謝謝了 不管你說要學多少東西,謙虛的人絕不會說那是錯的 作業系統我不會不懂,但要說哪一塊掛萬漏一恰好不熟,當然有可能 如果我比你高明,我說你作業系統不熟該重學 想必你也不會拒絕 問題在能不能點出章節,不然是不是要投入好幾個月甚至幾年?
Hsins: 我反倒覺得如果有資深工程師說從業十幾年,沒讀過作業系統 04/10 22:11
Hsins: ;而有人聽信去效法,卻落得基礎不扎實,資深只與從業時間 04/10 22:12
Hsins: 長短而無關能力,那才真的是在邯鄲學步… 04/10 22:12
Hsins: 不過我很支持你打造自己的除錯工具,但如果你有時間壓力, 04/10 22:28
Hsins: 多埋一些日誌會比較適合 04/10 22:28
這是同一回事,我的除錯工具,主要工作就是在埋日誌
s860134: 又是不讀完文件搞自幹 04/16 12:48
s860134: python 都能step by step debugging 你還在插扣 04/16 12:49
步進執行我有用喔.. 有用我還是解不了這個問題
wuyiulin: pdb 04/16 15:32
wuyiulin: 會推 pdb 是因為可以同時查多個變數 比 step by step 04/16 15:33
wuyiulin: 還有效率 04/16 15:33
wuyiulin: 然後也推看到什麼學什麼,目測要重看OS是對的xD 04/16 15:35
我不是說了嘛,我是 bug 已經解了,回頭看錯誤訊息,覺得錯誤訊息沒幫助 我可以把程式寫個很精簡的小範例重現 bug 但我還是不懂那和 OS 的關係在哪 何謂 thread? 那我乾脆就默了一段出來 以此代表在 OS 我也是了解這段的(而其他段或許不了解) 既然要說我對 OS 了解不夠 那是不是也默一段出來,說說我哪裡錯了?
s860134: 笑死 還查多個變數 又是不會用 debugging 的在搞笑 04/23 17:25
s860134: https://bit.ly/2kVHaP7 04/23 17:27
s860134: 如果你只會 pdb 還是乖乖插code 好嗎? 中斷點有用過? 04/23 17:28
s860134: 如果這些都不會 還是回去寫 C++, python 的功能對你雞肋 04/23 17:29
wuyiulin: 原來叫只會 pdb,閣下開發的時候都有IDE輔助 484寫網頁 04/23 19:22
wuyiulin: 的 484? 04/23 19:22
wuyiulin: 如果你是講 breakpoint() 那東西我印象等效 pdb 04/23 19:24
wuyiulin: 但是我目前 maintain 的專案版本沒有 breakpoint() 可 04/23 19:25
wuyiulin: 以用 所以也沒用過 就不妄評 04/23 19:25
wuyiulin: VSCode 的中斷點的話(燦笑) 04/23 19:25
s860134: ㄜ..... 沒用過就沒用過,pdb 跟你插扣沒兩樣 04/23 19:46
s860134: 我還建議你用 IPython.embed() 至少還有自動補完 04/23 19:47
s860134: 真的是不懂裝懂的一個樣,還以為你會說出用 GBD attach 04/23 19:47
s860134: 也是拉 反正都嘛看看 built in 和 for loop 怎麼寫就上工 04/23 19:50
s860134: 能寫 if else for loop 就算會 python 了 04/23 19:50
s860134: 怎麼 debugging cpython 自己跑一次看看吧 號稱寫C十幾年 04/23 19:56
s860134: 的應該會用? gdb? 04/23 19:56
不見得會 C 再熟,看別人程式也會需要重新熟悉 又不是別人程式用 C 寫的,而我寫 C 久了,我就一定能看懂 如果你是一定能看懂別人程式,其實你很優秀 :P 老實說我很久沒碰 C 了,但對 C 的語法一直是還在參考 因為一堆語言是 c like 啊,C 應該算我的基礎 gc, 垃圾搜集,c 沒有嗎? (啊,還真難一點,改說 c++ 好了) 在建構,解構式裡,埋 reference count 這些 其實也是慢慢發展出來的 更別說同樣是 c, 換了一套 ide, 結果環境不熟 但基本就是一樣,step, trace into.. 所以從 python 的直譯器去,會很快見到問題? 這想法有點怪,有點在 python 解不了,去找外掛的感覺 就好像 c 看程式解不了,去找執行檔反組譯成組合語言解的感覺 然後如果我說我組合語言寫十幾年 你回嗆說那當然可以直接看組合語言 啊。。組合語言是懂,但可讀性是那樣子 不在高階語言的高度直接解,不嫌辛苦? 我承認有個時候會需要進組合語言解: 懷疑 c compiler 本身有 bug,要看它做錯什麼時 但如果信任 c compiler, 這事我就不幹了...
wuyiulin: 我在跟你討論中斷點還有 pdb,這樣也可以拉 gdb 救援? 04/23 20:03
wuyiulin: g維拉 04/23 20:03
s860134: 我在跟你說怎麼 debugging ,你啥都不會 pdb? 04/23 20:04
s860134: 拜託 當你要加一行 pdb 進 code 裡就 lowwwww 掉了 04/23 20:04
s860134: 更何況 pdb 提供的功能如此原始,你這樣效率怎麼上工? 04/23 20:05
wuyiulin: 還好我上工的時候早就熟悉其他更 efficient 替代 for l 04/23 20:05
wuyiulin: oop 的方式,感謝你這麼關心別人的職涯欸。 04/23 20:05
s860134: 就是說你的方法沒效率 土炮 沒看文件 就這樣 04/23 20:06
※ 編輯: HuangJC (123.204.157.211 臺灣), 05/04/2023 03:40:36
s860134: 又是再講廢話... 05/06 17:05
s860134: 我貼的每一個方法都能直接顯示中斷的python code位址和當 05/06 17:07
s860134: 前變數值,即使多線程也能 不要沒用就先用你那狹隘的見解 05/06 17:07
s860134: 去評斷 05/06 17:07
s860134: 只是滿嘴專有名詞呼攏人的小白罷了 05/06 17:08
s860134: 我不關心你寫幾年 我只知道你學習能力很差而已 05/06 17:08
我學習能力差一樣不用你關心啊 我是什麼重要的人影響到你了嗎? 難道我說你學習能力很好,你能接受? 你沒這麼自大吧。。。 對我來說,我的重點只有'這個我不會' 其他不重要,也沒那麼自大 我相信我有多謙虛,你也有 ※ 編輯: HuangJC (123.241.134.39 臺灣), 12/01/2023 21:09:11