這幾天晚上群裡一朋友有償叫我把他的程式弄穩定,因為是現場管理專案,需要做到無人職守,所以即使是客戶端,也不能經常down機,因為之前對他的程式有過乙個晚上的實地檢視,基本流程已經有個大概的了解,我就接下來了。
剛開始的時候, 程式執行不到乙個上午,記憶體暴漲,有時幾個小時就掛了,這個那天晚上發現了,找了半天發現一處載入的tmemorystream沒有釋放。
沒想到接下來還有很多的坑需要填。
乙個個解決吧,看看有多少坑!
第一天:開始他跟我說他的連線資料庫老是超出數量,會導致程式不能處理任務,當天晚上就用diocp3中的basequeue做了個輕便的ado連線池,因為basequeue做了大量的測試,所以這個ado連線池經過簡單的測試就算ok了,接下來就大量的苦力工作了。
第二天:說連線池換上後,連線問題沒有了,可是執行緒池不能處理任務了。他之前使用的乙個叫uthreadpool單元,**好複雜。我推薦他使用qwokers,因為qwokers我一直在使用,很穩定了,任務的投遞也很簡單,後來一想,他是d7,沒辦法用這麼好的類庫,沒辦法,只好iocptask上了。iocptask diocp3中的乙個任務投遞的庫, 是個類似qworker的庫,不過只有任務投遞和執行的功能,比起qworker來說太簡單了,不過用iocpengine穩定性應該也是不錯的了。換上後,我接著對iocptask做了寫修改,加強了除錯資訊,能夠很方便的看到工作執行緒的當前狀態,和任務執行的狀態。
因為他說執行緒池有問題,我估計肯定是卡在哪個任務了,到時候卡死的時候一看就明白了。
下面是iocptask輸出的狀態資訊,
post counter:10000001
response counter:10000001
error counter:0
active : true, worker count: 5
----------------------- woker 1 --------------------
thread id: 9664, response count: 1719388
busying:false, waiting:true, reserved:true
request state info:
runinmainthread: false, done: true, time(ms): 0
----------------------- woker 2 --------------------
thread id: 6680, response count: 2010817
busying:false, waiting:true, reserved:true
request state info:
runinmainthread: false, done: true, time(ms): 0
----------------------- woker 3 --------------------
thread id: 4956, response count: 1965637
busying:false, waiting:true, reserved:false
request state info:
runinmainthread: false, done: true, time(ms): 0
----------------------- woker 4 --------------------
thread id: 8304, response count: 2641407
busying:false, waiting:true, reserved:false
request state info:
runinmainthread: false, done: true, time(ms): 0
----------------------- woker 5 --------------------
thread id: 9528, response count: 1662752
busying:false, waiting:true, reserved:false
request state info:
runinmainthread: false, done: true, time(ms): 0
因為是github上面的專案所以我用了e文注釋和e文資訊,中式英文,都懂的,稍微解釋下,
post counter:10000001 //代表投遞的任務數
response counter:10000001 //響應數
error counter:0 //投遞失敗數量
下面是工作執行緒的一些資訊,有執行緒id, 響應處理的任務數量,
下面的狀態比較關鍵
busying 的true的話就是代表正在執行任務,wating是在等待狀態, reserved是代表常駐工作執行緒
如果busying為true,會跟著出現當前正在執行的任務資訊,如果任務都在執行這樣執行緒池達到最多的執行緒數,就不能處理新的任務了。導致了他程式發生的情況。這樣可以根據任務的資訊找到對應的過程,去縮小範圍查詢問題。
request state info: 如果任務有備註資訊,會顯示在這裡
runinmainthread:是否在主線程執行的任務,done:任務是否完成, time(ms): 是任務耗用的時間。
有了iocptask這個坑很快找到了。
發現原來臨界用了很多,導致了任務死鎖…,
明天要接著填臨界的坑了。
第三天:他的程式臨界使用氾濫,當前進入不了臨界,導致任務掛起,但是並不是當前臨界的問題,是因為有其他任務進入臨界沒有退出。所以要找出前面的臨界,把臨界類改造了下。
可以看到臨界的當前資訊,我把iocplocker也進行了相應的公升級
function tiocplocker.getdebuginfo: string;
begin
result := format('%s: busycount:%d, try:%s, enter:%s', [self.fname, getentercount, ftryenterinfo, fenterinfo]);
end;
可以獲取臨界的名稱,進入嘗試進入臨界的執行緒個數,嘗試進入臨界的資訊和已經進入臨界的資訊。
有了這個資料就可以看到死鎖的臨界已經進入的臨界資訊就是代表造成死鎖的元凶了。
認真的對他的程式做了改進,並講解了多執行緒程式設計需要注意的地方《後面會總結》,雖然後面程式還有寫bug。他還是很爽快的把錢給付了,說即使程式還有問題也值了,通過這次填坑交流知道要注意很多地方。這算是對我這次工作的最大肯定吧。
總結:1.子執行緒千萬不要訪問主線程的ui,(memo,label),我發現這樣做的程式設計師很多,在diocp中經常會用到onconnected/ondisconnected事件中直接操作主窗體的memo。導致程式無法正常退出,或者出現卡死主介面的情況,原因我想可以歸納到訪問衝突上面,用臨界也不能解決問題。很多元件都是靠windows訊息驅動,他才不會使用零件去處理訊息,所以臨界也沒辦法。你只有老老實實的投遞到主線程去完成這部分工作,qworker和iocptask都可以很好的完成這項工作。
2.執行緒之間訪問共享資源需要用臨界,千萬不要多個執行緒同時去處理同乙個變數,或者列表,否則就等著出現各種問題吧。
3.資料庫連線盡量用連線池去完成,這樣既可以減少連線,也可以很好的避免多個執行緒對同乙個連線的使用。
當然還有很多細小的問題,需要自己去注意了。
python程式多執行緒 PYTHON多執行緒
在單執行緒的情況下,程式是逐條指令順序執行的。同一時間只做乙個任務,完成了乙個任務再進行下乙個任務。比如有5個人吃飯,單執行緒一次只允許乙個人吃,乙個人吃完了另乙個人才能接著吃,假如每個人吃飯都需要1分鐘,5個人就需要5分鐘。多執行緒的情況下,程式就會同時進行多個任務,雖然在同一時刻也只能執行某個任...
多執行緒筆記
1 stdin fileno 在unix一些系統呼叫中使用到stdin fileno表示標準輸入,stdout fileno表示標準輸出,stderr fileno表示標準出錯,使用時需要加標頭檔案 在unix下還有stdin,stdout,stderr表示同樣的含義。stdin fileno與st...
多執行緒筆記
一.程序 就是cpu所要執行的乙個任務 自己理解的 執行緒 執行緒是乙個併發執行的順序流,乙個程序包括多個順序執行流程,這執行流程稱為執行緒 就是任務中許多的 二.執行緒排程分配cpu的時間片段給不同的執行緒,得到時間片段的執行緒被cpu執行,其他執行緒等待,執行緒排程會盡可能的分配時間片段取執行。...