網路城邦
上一篇 回創作列表 下一篇  字體:
如何高速反覆拷貝電腦螢幕,保持穩定不當機的程式!
2022/03/09 04:35:10瀏覽2115|回應0|推薦8

相信很多處理Windows作業系統下的影像物件(Bitmap)操作的程式師,都會將GDI+視為夢魘!理論上,影像物件好像應該與一般的陣列物件一樣,你就宣告使用就好,但事實上當你頻繁反覆使用這些程式時,常常會出現一些莫名其妙的錯誤,慘遭當機的災情!

譬如上圖顯示的New Bbitmap程式碼,如果你是使用某個變數,譬如 w = 1280,h = 720,Bitmap(w, h) 作為參數,即使你一直沒有改變變數w與h的值,當你高頻率反覆執行這個宣告時,在執行幾萬次之後,它就會忽然跳出「參數錯誤」的錯誤!我的動態車牌辨識軟體需要一秒鐘十幾二十次的反覆擷取螢幕影像,如果程式跑個幾小時之後就當機,我的生意就難做了!

很多人一直質疑我為何堅持用拷貝螢幕來取得影像?為何不直接從串流資料,或攝影機直接取得影像進行辨識?其實我都試過了!但是我發現這些工作就是顯示卡硬體這些年來努力精進的工作,我如果想用軟體取代顯示卡的功能,才是愚蠢的嘗試!就像勤練體能試圖不必買車每天長跑幾十公里去上班一樣的蠢顯示卡的這種能力進化是因為越來越多人用電腦看網路視訊,還記得那個看YouTube會一直卡卡的年代嗎?那就是顯示卡串流解碼能力差,甚至還在用CPU解碼的緣故!

拷貝螢幕取得影像其實是抄捷徑,利用顯示卡的高效率解串流取得原始影像的能力,當它們把可以作影像辨識的單一影像PO上螢幕時,我再使用拷貝螢幕的動作取得我需要的影像。其實就跟現在很多人都不再自己下廚煮飯,直接呼叫外賣,請FoodPandaUberEat送過來一樣!

在這種機制的比擬之下,顯示卡就是專業餐廳,FoodPandaUberEat就是我寫的GDI+程式碼了!我面臨的問題是外送員沒有如預期的永遠保持使命必達!送個幾萬次之後就會開始倦勤,越送越慢最後乾脆不理我了!我給的訂餐叫貨指令當然都是一樣的,用太頻繁久了卻會失效?我該怎麼辦呢?

好像隔靴搔癢,我也只能讓外送員的工作簡化,讓他們的工作簡單輕鬆到根本不會出意外!所以經過好幾年的經驗累積,我可以告訴你:如果New Bitmap宣告時直接使用常數,它就會永遠穩定!不會忽然出現奇怪的「參數錯誤」了?

但即使如此,當你用Graphics物件反覆拷貝螢幕幾萬次之後,還是會出現意外的錯誤!所以我都會用Try Catch的錯誤捕捉程式防範,一旦出現意外就重新宣告Graphics物件,希望可以像丟掉老舊機車,買新的機車一樣,再用個好多年!

但是因為我不知道的GDI底層程式的某些缺陷,重新設定的Graphics物件不會像全新機車一樣可以使用那麼久?首次宣告的Graphics如果可以用五萬次,重新宣告的Graphics可能就是使用一萬次,接下來每次重新宣告就年限越來越短,最終還是當機了!

讓我尷尬痛苦的是:如果一樣的程式,在最好的i9電腦執行可能是永遠沒事的!拿到i7呢?一兩天之內就跌跌撞撞到最後當機了!我應該要求客戶都買超級電腦嗎?那可是成本啊!我是軟體廠商如何告訴客戶我的軟體會當機是硬體太差呢?電腦等級差跑得慢可以理解,會當機就很難自圓其說了!

經過痛苦的實驗測試煎熬,我得到的解決方案還是簡化參數!如上圖程式碼CopyFromScreen參數都用常數就穩定多了!但還是大約一天的時間就有可能出事!我只能抓瞎式的嘗試一些程式機制,譬如用GC.Collect清理記憶體之類的!

最後的答案是如圖所示的SynLock效果最佳!在拷貝螢幕時,如果加上它就幾乎完全不會出現意外錯誤了!其實很詭異,理論上這個程式碼是用於防範其他執行緒存取目前(拷貝螢幕)動作需要使用的記憶體,但是我的程式中並沒有其他執行緒會干擾到螢幕拷貝才對?

事實勝於雄辯,最終我也只能使用實驗測試結果最穩定的程式碼!為何如此?我也只能用想像解釋,或許為了效能考慮,GDI+的底層動作沒有很嚴謹的防範整個作業系統中其他的程式執行緒來干擾它!我用SynLock算是幫它補足了防災機制吧?

我其實很掙扎,要不要告訴大家我經過長時間的慘痛經驗得到的這個經驗技巧?但是想想我曾經從網路論壇上得到過的種種協助,這也不是甚麼偉大的理論發明?就是嘗試錯誤適應現階段現實世界問題的經驗而已,不久之後GDI+改版,這些莫名其妙的錯誤可能就不會再出現了,我的程式技巧也就沒意義了!

所以我還是決定能助人時就及時行善!善用我的經驗,你現在就可以跟我一樣,開發出使用高速大量拷貝螢幕取得影像的穩定軟體了!不必痴痴等待微軟的GDI+再改版,或甚麼GPU硬體的升級進化推出新的硬體產品了!我們現在就必須推出軟體產品討生活,不是嗎?不然你我的軟體公司就要難過倒閉了!

( 心情隨筆工作職場 )
回應 推薦文章 列印 加入我的文摘
上一篇 回創作列表 下一篇

引用
引用網址:https://classic-blog.udn.com/article/trackback.jsp?uid=yccsonar&aid=171945174