R程式除錯與效能提升設計
# R程式錯誤種類
# 除錯方法
# 除錯實務應用
# shiny除錯
# 效能提升
(1)語法錯誤(Syntax Errors)
(2)編譯時期的錯誤(Complie Errors)
(3)執行時期錯誤(Run-time Errors)
(4)邏輯錯誤(Logical Errors)
1.1 語法錯誤
各種程式語言皆有其語法的規範,在撰寫程式過程中,如果程式不符合語法的規範,則會產生語法錯誤。語法錯誤可經由GUI編輯器,直接顯示錯誤訊息,例:R語言的免費GUI編輯器-RStudio(https://www.rstudio.com/products/RStudio/)。
例如:if 編輯if為IF,括號沒有成對使用,沒有先行匯入套件(Packages),結尾忘了加上「:」。
參考圖1 R語法錯誤,圖1上方 with bug 區塊中顯示語法錯誤「if 打成IF」,下方 complete debug 區塊中顯示已改為小寫if的正確結果。
1.2 編譯時期的錯誤
編譯時期的錯誤可以透過「編譯器(Compiler)」在編譯的時候就發現問題,較容易找出錯誤。
1.3 執行時期錯誤
執行時期的錯誤就比較難追蹤,執行階段錯誤所控制的程式設計師,比方說,「 網路服務無法使用 」 的錯誤。或二個數值相除,分母為零的錯誤。此階段可依據錯誤訊息而修正錯誤。
1.4 邏輯錯誤
邏輯錯誤所造成的程式設計錯誤,例如,「 索引超出範圍 」 錯誤。使用者輸入不符合預期數值資料,例如,輸入英文字元。
程式錯誤情境中會有所謂例外(Exception),例外指的是程式發生不正常的錯誤,而導致無法繼續執行的情形。有的時候,僅管程式語法完全正確,當執行程式時仍然會有錯誤。這種在程式執行階段發生的錯誤亦稱為例外 ( exceptions ) ,並且會造成程式完全的終止且程式無法繼續執行。
2.1 發現程式錯誤的存在
在除錯前除了找出錯誤的現象,先備份原始程式碼或使用版本管理工具,亦是踏出基礎的原始碼管理的第一步。
2.2 小範圍逐步確認
以隔離、消除的方式對錯誤進行確認。例如:一次只修改一段程式區塊。
2.3 確定錯誤產生的原因
此步驟包括尋找類似的錯誤並查詢是否有類似的程式需要一併修正。
2.4 找出修正錯誤的解決辦法
此步驟可依不同程式語言所提供的除錯工具並找出修正錯誤的解決辦法。
2.5 修正錯誤,重新測試
最後依解決辦法進行修正錯誤並重新測試。
關於程式除錯,須注意以下的特性:
程式即便是正常執行,仍有可能隱藏錯誤
經過完整測試後的程式,亦有可能會有錯誤
語法錯誤(Syntactic errors)一般編譯器都會找出來這種錯誤
語義錯誤(Semantic errors)是編譯器所無法檢查出來的錯誤
良好的測試案例與清晰的程式碼註解可增近除錯的效率
典型除錯技術包括:
(1)單步執行(Single-stepping)
(2)插入中斷點(Breakpoint)
(3)新增並追蹤額外變數法
(4)在問題點附近加入Try/Catch等方式以利於鎖定錯誤範圍
3.1 traceback()
如果程式錯誤並已完全終止,此時立即使用 traceback 將顯示錯誤前的最近執行的語法。
參考圖2 traceback 除錯結果,圖中顯示 traceback 會採用由上至下的方式取出錯誤堆疊(Stack)的結果,因此先顯示h(b)第2行的錯誤訊息,其次為g(a),最後才是f(1)。
3.2 debug()
traceback 只能指出錯誤的發生處,並不能幫助使用者找出程式的錯誤。debug 可以逐行執行並提供互動式的除錯功能。debug 提供函數作為參數輸入,因此對於使用者建立或內建函數除錯提供更有用的除錯資訊。完成除錯後可使用 undebug 來移除 debug 功能。debug 可以輸入下四種指令與R函數,例:ls()函數:
n 繼續執行下一行程式,按下[Enter]鍵亦可。
c 繼續執行後續所有程式並回傳結果。
Q 中斷程式。
where 顯示呼叫所有函數堆疊。
參考圖3 debug 除錯結果,考慮計算總平方差(Sum of Squared Differences,SSD)並建立SSD函數,僅接著使用n與ls函數()進行debug除錯。
3.3 browser()
在上述 debug() 函數中可以逐行除錯,如果希望在特定程式碼中進行除錯,此時可使用 browser() 函數,將程式暫時中斷並等待使用者輸入。
參考圖4 browser 除錯結果,考慮修正上個步驟計算總平方差並建立SSD函數。
3.4 try()
參考圖5 try 除錯結果,考慮log輸入不正確字元參數 RWEPA,其結果會顯示Error而中斷程。修正後加上 try 函數即可繼續執行後續程式並顯示log(3)之結果。try(…, silent=TRUE)函數,其結果會隱藏錯誤訊息。
3.5 tryCatch()
參考圖6 tryCatch除錯,如果希望針對錯誤(Error)或警告(Warning)等不同情形,提供對應的解決方式,此時可考慮使用 tryCatch 函數。範例中分別加上 warning 與 error 的處理方式,因此程式不會中上,而可顯示不同結果。
3.6 withCallingHandlers()
withCallingHandlers 與 tryCatch 功能類似。主要有兩大區別,分別參考圖7 withCallingHandlers除錯-回傳值與圖8 withCallingHandlers除錯-運作方式與以下說明:
tryCatch()處理程序的回傳值由tryCatch()定義,而 withCallingHandlers()的回傳值會被忽略,參考圖7。
使用sys.calls()查閱對應的中間過程,withCallingHandlers 的運作方式相當於 traceback 用法,如下所示,它列出了導致當前函數的所有調用,參考圖8。
(1)採用矩陣運算
(2)使用圖形處理器(graphics processing unit,GPU)運算
(3)使用平行運算處理技術,主要包括資料平行處理和工作平行處理(data parallelism and task parallelism)。
# R程式錯誤種類
# 除錯方法
# 除錯實務應用
# shiny除錯
# 效能提升
1. R程式錯誤種類
在1947年9月9日,葛麗絲·霍普(Grace Hopper)發現了第一個電腦上的bug。因此,人們逐漸開始用「Bug」(原意為「蟲子」)來稱呼電腦中的隱藏錯誤。即程式執行時,畫面顯示錯誤或整個程式沒反應,此時一般稱呼程式產生臭蟲(Bug),僅接著是找出臭蟲並進行錯誤修正,此步驟稱為除錯或偵錯(Debug),常見的程式錯誤包括以下四種情形,以下分別說明其內容。(1)語法錯誤(Syntax Errors)
(2)編譯時期的錯誤(Complie Errors)
(3)執行時期錯誤(Run-time Errors)
(4)邏輯錯誤(Logical Errors)
1.1 語法錯誤
各種程式語言皆有其語法的規範,在撰寫程式過程中,如果程式不符合語法的規範,則會產生語法錯誤。語法錯誤可經由GUI編輯器,直接顯示錯誤訊息,例:R語言的免費GUI編輯器-RStudio(https://www.rstudio.com/products/RStudio/)。
例如:if 編輯if為IF,括號沒有成對使用,沒有先行匯入套件(Packages),結尾忘了加上「:」。
參考圖1 R語法錯誤,圖1上方 with bug 區塊中顯示語法錯誤「if 打成IF」,下方 complete debug 區塊中顯示已改為小寫if的正確結果。
圖1 R語法錯誤
1.2 編譯時期的錯誤
編譯時期的錯誤可以透過「編譯器(Compiler)」在編譯的時候就發現問題,較容易找出錯誤。
1.3 執行時期錯誤
執行時期的錯誤就比較難追蹤,執行階段錯誤所控制的程式設計師,比方說,「 網路服務無法使用 」 的錯誤。或二個數值相除,分母為零的錯誤。此階段可依據錯誤訊息而修正錯誤。
1.4 邏輯錯誤
邏輯錯誤所造成的程式設計錯誤,例如,「 索引超出範圍 」 錯誤。使用者輸入不符合預期數值資料,例如,輸入英文字元。
程式錯誤情境中會有所謂例外(Exception),例外指的是程式發生不正常的錯誤,而導致無法繼續執行的情形。有的時候,僅管程式語法完全正確,當執行程式時仍然會有錯誤。這種在程式執行階段發生的錯誤亦稱為例外 ( exceptions ) ,並且會造成程式完全的終止且程式無法繼續執行。
2. 除錯方法
除錯的基本五大步驟:2.1 發現程式錯誤的存在
在除錯前除了找出錯誤的現象,先備份原始程式碼或使用版本管理工具,亦是踏出基礎的原始碼管理的第一步。
2.2 小範圍逐步確認
以隔離、消除的方式對錯誤進行確認。例如:一次只修改一段程式區塊。
2.3 確定錯誤產生的原因
此步驟包括尋找類似的錯誤並查詢是否有類似的程式需要一併修正。
2.4 找出修正錯誤的解決辦法
此步驟可依不同程式語言所提供的除錯工具並找出修正錯誤的解決辦法。
2.5 修正錯誤,重新測試
最後依解決辦法進行修正錯誤並重新測試。
關於程式除錯,須注意以下的特性:
程式即便是正常執行,仍有可能隱藏錯誤
經過完整測試後的程式,亦有可能會有錯誤
語法錯誤(Syntactic errors)一般編譯器都會找出來這種錯誤
語義錯誤(Semantic errors)是編譯器所無法檢查出來的錯誤
良好的測試案例與清晰的程式碼註解可增近除錯的效率
典型除錯技術包括:
(1)單步執行(Single-stepping)
(2)插入中斷點(Breakpoint)
(3)新增並追蹤額外變數法
(4)在問題點附近加入Try/Catch等方式以利於鎖定錯誤範圍
3. 除錯實務應用
在除錯實務應用中,R語言提供以下除錯函數,以利於錯誤發生時,允許程式設計師採取某些行動,進而達到除錯目的。3.1 traceback()
如果程式錯誤並已完全終止,此時立即使用 traceback 將顯示錯誤前的最近執行的語法。
參考圖2 traceback 除錯結果,圖中顯示 traceback 會採用由上至下的方式取出錯誤堆疊(Stack)的結果,因此先顯示h(b)第2行的錯誤訊息,其次為g(a),最後才是f(1)。
圖2 traceback除錯
3.2 debug()
traceback 只能指出錯誤的發生處,並不能幫助使用者找出程式的錯誤。debug 可以逐行執行並提供互動式的除錯功能。debug 提供函數作為參數輸入,因此對於使用者建立或內建函數除錯提供更有用的除錯資訊。完成除錯後可使用 undebug 來移除 debug 功能。debug 可以輸入下四種指令與R函數,例:ls()函數:
n 繼續執行下一行程式,按下[Enter]鍵亦可。
c 繼續執行後續所有程式並回傳結果。
Q 中斷程式。
where 顯示呼叫所有函數堆疊。
參考圖3 debug 除錯結果,考慮計算總平方差(Sum of Squared Differences,SSD)並建立SSD函數,僅接著使用n與ls函數()進行debug除錯。
圖3 debug除錯
3.3 browser()
在上述 debug() 函數中可以逐行除錯,如果希望在特定程式碼中進行除錯,此時可使用 browser() 函數,將程式暫時中斷並等待使用者輸入。
參考圖4 browser 除錯結果,考慮修正上個步驟計算總平方差並建立SSD函數。
圖4 browser除錯
3.4 try()
參考圖5 try 除錯結果,考慮log輸入不正確字元參數 RWEPA,其結果會顯示Error而中斷程。修正後加上 try 函數即可繼續執行後續程式並顯示log(3)之結果。try(…, silent=TRUE)函數,其結果會隱藏錯誤訊息。
圖5 try除錯
3.5 tryCatch()
參考圖6 tryCatch除錯,如果希望針對錯誤(Error)或警告(Warning)等不同情形,提供對應的解決方式,此時可考慮使用 tryCatch 函數。範例中分別加上 warning 與 error 的處理方式,因此程式不會中上,而可顯示不同結果。
圖6 tryCatch除錯
3.6 withCallingHandlers()
withCallingHandlers 與 tryCatch 功能類似。主要有兩大區別,分別參考圖7 withCallingHandlers除錯-回傳值與圖8 withCallingHandlers除錯-運作方式與以下說明:
tryCatch()處理程序的回傳值由tryCatch()定義,而 withCallingHandlers()的回傳值會被忽略,參考圖7。
圖7 withCallingHandlers除錯-回傳值
使用sys.calls()查閱對應的中間過程,withCallingHandlers 的運作方式相當於 traceback 用法,如下所示,它列出了導致當前函數的所有調用,參考圖8。
圖8 withCallingHandlers除錯-運作方式
4. shiny除錯
shiny套件是網頁應用程式,一般只有在shiny程式執行時,才會顯示程式是否正常執行。例:在"01_hello" 範例中,如果須測試 input 輸入控制項之結果,則可在bins之前先行輸入 # input <- list(bins=30) 前面加上#,以免正式執行時,永遠bins為30。總而言之,輸入控制可於input中宣告為list,以利事先了解其執行結果或加速shiny除錯,詳細結果參考圖9所示。library(shiny)
runExample("01_hello")
output$distPlot <- renderPlot({
x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)
圖9 shiny除錯
5. 效能提升
一般考慮以下方式,可提升程式執行效能:(1)採用矩陣運算
(2)使用圖形處理器(graphics processing unit,GPU)運算
(3)使用平行運算處理技術,主要包括資料平行處理和工作平行處理(data parallelism and task parallelism)。
PREVIOUSR軟體中文數字轉換