2011-02-02 68 views
3

我正在編寫一個Android應用程序。據我所知,設備中的大多數SD卡都具有〜4Mb/s的寫入速度。在最糟糕的情況下,我的應用程序需要創建一個約0.5Mb的新文件並將其寫入約5次。一般來說,這樣做時IO速度非常快,但是在短時間內創建並寫入多個文件後,我經歷了大約2秒的突然等待時間。定期寫入數據時隨機長時間IO暫停

下面是我的應用程序的一些統計數據(注意,只有一個IO操作在時間永遠跑):

E = Time IO operation began 
S = Number of Mbs written 
WT = Time taken to write to file 

E  S  WT  
14.546 ~0.41 MB 0.02s 
15.061 ~0.40 MB 0.019s 
15.600 ~0.42 MB 0.073s 
16.054 ~0.41 MB 0.02s 
16.538 ~0.36 MB 0.019s 
17.007 ~0.33 MB 0.018s 
17.475 ~0.32 MB 0.017s 
18.030 ~0.38 MB 0.07s 
19.991 ~0.38 MB 1.542s <-- 
20.124 ~0.34 MB 0.018s 
20.233 ~0.25 MB 0.015s 
20.390 ~0.38 MB 0.021s 
20.624 ~0.36 MB 0.08s 
20.858 ~0.37 MB 0.018s 
21.304 ~0.32 MB 0.018s 
21.796 ~0.33 MB 0.017s 
22.257 ~0.35 MB 0.02s 
22.780 ~0.37 MB 0.07s 
24.366 ~0.27 MB 1.178s <-- 
24.522 ~0.40 MB 0.021s 
24.648 ~0.34 MB 0.019s 
24.866 ~0.38 MB 0.018s 
25.319 ~0.29 MB 0.07s 
25.850 ~0.45 MB 0.021s 
26.288 ~0.39 MB 0.018s 
26.796 ~0.43 MB 0.035s 
27.249 ~0.33 MB 0.069s 
27.671 ~0.41 MB 0.018s 
30.054 ~0.44 MB 1.874s <-- 

注意,大部分的IO操作的完成在< 0.05秒,但是,在大約8寫操作總共寫入約4Mb的數據,下一次IO操作需要約1.5s。這是爲什麼發生?這種模式發生得相當一致。

我的文件正被寫入下面的代碼(我不沖洗或同步):

RandomAccessFile fos = new RandomAccessFile(filename, "rw"); 
    FileChannel outChannel = fos.getChannel(); 
    byteBuffer.rewind(); 
    outChannel.write(byteBuffer); 
    fos.close(); 

我在文件IO方面的專家,但我知道快速IO操作次數指明的不是招數據實際上還沒有寫入磁盤,大的暫停可能是緩衝區被刷新。我如何避免暫停?看起來好像我的IO操作很小且不經常發生,所以我應該能夠避免這種暫停。

對於某些上下文:我使用帶紀念品的命令模式在用戶可以執行許多破壞性操作的上下文中實現撤銷/重做。我無法將記憶存儲在內存中,因爲我沒有足夠的內存,所以我會將記錄寫入磁盤。除了上述暫停問題之外,這種方法非常棒,因爲這意味着用戶界面不得不等待IO完成,並且1.5秒的滯後對用戶來說太隱蔽了。我知道還有其他的是實施撤消/重做,但每種方法都有缺陷。

回答

3

這是怎麼發生的?

歡迎使用flash。

我不是文件IO方面的專家,但我知道快速IO操作時間表明數據還沒有實際寫入磁盤,而大暫停可能是緩衝區被刷新。

可能不是。據我瞭解,大多數Android設備都使用YAFFS2文件系統,該文件系統不會緩衝數據。但是,它們具有每個分區的寫入鎖定,因此您的暫停可能在其他任何內容寫入閃存時發生。

隨着更多的Android設備(例如Nexus S)運行ext4文件系統,然後flushing/syncing becomes important

另外,要記住,閃爍的寫入速度會由各種其它因素,如文件系統是如何充分變化,對特定細胞損耗平衡的狀態被嘗試,等等

您可能希望在「編寫Zippy Android應用程序」時觀看Brad Fitzpatrick的2010 Google I|O presentation,因爲他詳細介紹了這一點。

我該如何避免暫停?

你不知道。您可以通過AsyncTask將Flash I/O移動到後臺線程。 Android 2.3中的新的StrictMode將幫助您確定您擁有這樣「janky」代碼的位置。

+0

呃,這很令人失望。我希望我的撤銷/重做堆棧在應用程序會話之間持續存在,因此我需要在某個時刻將這些堆棧保存到磁盤。命令對象也可以增長到相當大的尺寸,所以我需要有一個後臺進程將它們寫入磁盤,因爲它們是創建的。儘管IO寫入次數不可預知,但如何在我的應用程序被中斷的情況下確保在onPause被調用的時候確保將所有寫入磁盤的內容都不明確。如果我需要在每個文件上調用.sync(),情況會更糟。有什麼建議? – rbcc 2011-02-02 01:13:28