今天在用JMeter對公司的程式作壓力測試,但是我發現錯誤率一直在0.5~1%,這是相當高的錯誤率,所以就來查啦。
從JMeter紀錄來看,錯誤訊息是這樣
原本的code長的這樣
我先改成用Using StreamWriter,原因可以看這邊using Statement,但是再次測試時,發現錯誤率雖然降低了,可是還是有錯,這是不容許的啊!! 最後一時找不到方法,只好加上lock,然後就再也測不到 IOException 的錯誤,可以算是解決問題了,但是我想搞不好有更好的方法就是。
最後code改成這樣
話說我後來找到一個非同步檔案 I/O,不曉得能不能解這種問題就是....
2012/08/16 update
之前壓力測試時,因為在本機測試,每秒跑不到100次,所以用之前的方式就可以避掉file lock的問題,後來搬到測試機上測試,加上程式效能又調教過,變成每秒可以跑500~600次,這時候又遇到IOException的問題了,剛遇到時,試了一些方法,都還是會有問題,不然就是搞到Out of memory XD ,原本都已經在看非同步存取的方式能不能解了,沒想到昨天晚上打LOL之前,又找了一下幾種可能的解法,今天到公司一試,還真的解掉了這問題。
在找解法的時候,也試過3rd party 的logging方式,如 NLog、log4net ,但是效能都會被拖到剩下1/3不到,只剩每秒不到200次,後來還是回頭自己寫效率比較好。
而IOException在目前的測試下是還沒有發生過,速度也不會慢很多,所以這解法暫時是可以work的,等壓力測試能跑到更高的數值的時候,再看看有沒有需要改吧。
從JMeter紀錄來看,錯誤訊息是這樣
System.IO.IOException: 由於另一個處理序正在使用檔案 'filename',所以無法存取該檔案。原因是在程式中會去對實體檔案寫log,平時看不出錯誤,但是壓力測試下就會因為檔案lock住產生 IOException 。
System.IO.IOException: The process cannot access the file 'filename' because it is being used by another process.
原本的code長的這樣
public static void WriteLog() { StreamWriter log; if (!File.Exists("FilePath")) { log = new StreamWriter("FilePath"); } else { log = File.AppendText("FilePath"); } log.WriteLine("Write Something"); log.Close(); }
我先改成用Using StreamWriter,原因可以看這邊using Statement,但是再次測試時,發現錯誤率雖然降低了,可是還是有錯,這是不容許的啊!! 最後一時找不到方法,只好加上lock,然後就再也測不到 IOException 的錯誤,可以算是解決問題了,但是我想搞不好有更好的方法就是。
最後code改成這樣
private static readonly object LockFile = new object(); public static void writeFile() { lock(LockFile) { using (var log = new StreamWriter("FilePath", true)) { log.WriteLine("Write Something"); } } }題外話,StreamWrite有個StreamWriter Constructor (String, Boolean)可以自動判斷沒檔案就新增,有檔案就加在後面,所以不用自己判斷了。
話說我後來找到一個非同步檔案 I/O,不曉得能不能解這種問題就是....
2012/08/16 update
之前壓力測試時,因為在本機測試,每秒跑不到100次,所以用之前的方式就可以避掉file lock的問題,後來搬到測試機上測試,加上程式效能又調教過,變成每秒可以跑500~600次,這時候又遇到IOException的問題了,剛遇到時,試了一些方法,都還是會有問題,不然就是搞到Out of memory XD ,原本都已經在看非同步存取的方式能不能解了,沒想到昨天晚上打LOL之前,又找了一下幾種可能的解法,今天到公司一試,還真的解掉了這問題。
private static readonly object LockFile = new object(); public static void writeFile() { using (var fs = new FileStream(filePath,FileMode.Append,FileAccess.Write,FileShare.ReadWrite)) { using (var log = new StreamWriter(fs)) { lock (LockFile) { log.WriteLine(logtxt); } } } }說穿了也就只是用FileStream設定正確的FileShare權限而已,沒想到這麼簡單就解決了 -_-
在找解法的時候,也試過3rd party 的logging方式,如 NLog、log4net ,但是效能都會被拖到剩下1/3不到,只剩每秒不到200次,後來還是回頭自己寫效率比較好。
而IOException在目前的測試下是還沒有發生過,速度也不會慢很多,所以這解法暫時是可以work的,等壓力測試能跑到更高的數值的時候,再看看有沒有需要改吧。
您好,我也在工作上遇到相同問題,明明已經用lock{}鎖住存取檔案的區塊,單依舊會發生
ReplyDeleteSystem.IO.IOException: 由於另一個處理序正在使用檔案 'filename',所以無法存取該檔案。
的狀況,所以想請教您,為何已經用了lock還是無法避免呢?為何還需要用到你所寫的第三種方法(設定正確的FileShare權限)呢?