DEBUG日記:同樣的代碼在不同的環境卻得出不同的結果。

 案例一:

  由於成員變量的初始化寫在了構造方法裏,以致於原本每次模型計算都要初始化一次,變成了創建一次對象才初始化一次,一批量的計算才初始化一次。

 現象:在WINDOWS的本地測試類上單次計算調試結果正確,而相同的代碼放到LINUX上批量計算結果錯誤。

剛開始發現Linux上批量計算出來的結果非常離譜,我們首先想到的就是包打錯了。我們的代碼分爲兩塊,一塊是JAVA從數據庫取模型的輸入參數,然後JAVA調用C++進行模型計算,計算結果返回JAVA再入數據庫。我們檢查Linux打的包大小和測試環境上的包大小是否一樣,結果發現是一樣的。接着我們推測是不是隻修改了程序的部分內容導致包大小沒有明顯變化。我們重新打了C++和JAVA的包,發現現象還是一樣。本地上單步調試就是和Linux上跑出來的結果不一樣。當時我們的測試類只支持單次模型計算而不支持批量計算。我們壓根就沒有想到是代碼的問題,而想的是環境問題和配置問題。因爲經過代碼比對,我的本地上的代碼和打包的代碼是完全一致的,我本地上單次計算模型結果都正確,就認爲代碼是正確的。Linux上不能像本地一樣設斷點單步調,只好不斷的加日誌,查日誌。然而多進程同時批量計算寫的卻是同一個日誌文件,導致日誌是混起來的。那就關掉多餘進程只留一個進程,這樣日誌就不會混了。但是計算量賊大,進程關了只剩1個,每一次全流程計算都耗了大量時間,但是結果就是和本地的不一樣,絕不絕望?日誌文件很大,且沒有把輸入參數的主鍵ID傳到C++裏,導致我本地上測的模型參數在日誌文件裏很難定位出來。我堅信我的代碼沒問題,要不然我在本地上跑出來的結果就不會正確了。查這問題重上午到第二天凌晨,人都傻了,細想每一步有沒有可能出錯,不斷的試驗,啥辦法都試過了。最後陪加班的組長建議,把本地上的測試類改成和Linux上的流程一致,改成支持批量計算。我依舊認爲是環境問題,而不是代碼問題,改測試類是浪費時間,時間又很晚了,改代碼的慾望十分低落,但還花了點時間把代碼改了,不抱希望的地丟了幾筆參數跑跑看。他孃的,居然錯誤復現了。不花兩分鐘的時間就定位出了問題把它改了。

代碼原因,每個計算任務都是跑一批模型輸入參數的,但每個任務只創建一次同種類型的模型輸入參數對象。我把輸入參數的默認值初始化寫在了構造方法裏,每次計算都要求初始化纔行。在構造方法裏初始化模型參數的結果就是一批模型參數只被初始化一次,所以跑單筆模型參數是復現不出問題的。

案例二:

 模型參數的組合主鍵新增了一個"場景"字段,而代碼中用HashMap進行緩存的key沒改,導致不同"場景"下的模型輸入參數不同,但是不同"場景"的計算結果卻完全一樣。

現象:導致不同"場景"下的模型輸入參數不同,但是不同"場景"的計算結果卻完全一樣。

立馬決定要復現問題,単測了一筆模型輸入,發現和Linux上跑的結果不一樣。首先把測試類改成支持多"場景"。接着在本地準備和Linux上測試條件,這是一個繁瑣的過程...最後由於測試條件不是完全一致,計算結果本地和Linux上跑的結果不一樣,但這並不是問題,因爲Bug現象被成功復現了,所有不同“場景”下取的參數不同,結果卻全部一樣。

最後發現是緩存中的Key值沒有加上"場景"字段,Key依舊是原來的id主鍵,導致取的關聯參數都是第一個相同id模型參數的關聯參數。所以計算的結果都是第一個同id的模型參數的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章