2009-07-20 60 views
0

我正在開發一個應用程序,它利用非常大的查找表來加速數學計算。這些表中最大的是一個int [],它有大約1000萬條記錄。並非所有的查找表都是int []。例如,一個是包含約200,000個條目的字典。目前,我生成每個查找表一次(這需要幾分鐘),並用下面的代碼片斷它序列到磁盤(與壓縮):存儲大型查找表

int[] lut = GenerateLUT(); 
    lut.Serialize("lut"); 

其中序列化的定義如下:

public static void Serialize(this object obj, string file) 
    { 
     using (FileStream stream = File.Open(file, FileMode.Create)) 
     { 
      using (var gz = new GZipStream(stream, CompressionMode.Compress)) 
      { 
       var formatter = new BinaryFormatter(); 
       formatter.Serialize(gz, obj); 
      } 
     } 
    } 

的我遇到的煩惱是啓動應用程序時,這些查詢表的反序列化時間很長(15秒以上)。這種類型的延遲會令用戶惱火,因爲應用程序將無法使用,直到加載所有查找表爲止。目前,反序列如下:

 int[] lut1 = (Dictionary<string, int>) Deserialize("lut1"); 
    int[] lut2 = (int[]) Deserialize("lut2"); 
... 

,其中作爲反序列化的定義:

public static object Deserialize(string file) 
    { 
     using (FileStream stream = File.Open(file, FileMode.Open)) 
     { 
      using (var gz = new GZipStream(stream, CompressionMode.Decompress)) 
      { 
       var formatter = new BinaryFormatter(); 
       return formatter.Deserialize(gz); 
      } 
     } 
    } 

起初,我認爲這也許已經是gzip壓縮是造成增速放緩,但刪除它只有脫脂從序列化/反序列化例程幾百毫秒。

任何人都可以提出一種方法來加快應用程序的初始啓動時這些查詢表的加載時間?

回答

2

首先,在後臺線程中反序列化會阻止應用程序在這種情況發生時「掛起」。僅此一項可能足以照顧你的問題。

但是,一般而言,序列化和反序列化(特別是大型字典)的反序列化速度往往非常緩慢。根據數據結構的不同,編寫自己的序列化代碼可以顯着加快速度,特別是在數據結構中沒有共享引用的情況下。

這就是說,根據這種使用模式,數據庫可能是一個更好的方法。你總是可以做出更多面向數據庫的東西,並且從數據庫中以懶惰的方式構建查找表(即:在LUT中查找查找,但如果查找不存在,則從數據庫加載並保存它在表中)。這將使啓動瞬間(至少在LUT方面),並可能仍然保持查找相當活潑。

0

我想明顯的建議是加載它們在後臺。一旦應用程序啓動,用戶已經打開他們的項目,並選擇他們想要的任何操作,剩下的15秒內就不會有太多時間等待。

+0

我同意這一點,但它是一種解決辦法還是有點海事組織。關於我的應用程序,gui非常簡單,用戶可以在5秒內完成計算。所以目前,我正在爭取5秒或更少的加載時間(查找表將在不到5秒的時間內加載到後臺)。 – snazzer 2009-07-20 23:59:36

0

我們在這裏談論的數據量是多少?根據我的經驗,從磁盤讀取一千兆字節到內存大約需要20秒。所以如果你讀半個GB以上,你幾乎肯定會遇到硬件限制。

如果數據傳輸速率不是問題,那麼實際的反序列化需要時間。如果有足夠的內存,可以將所有表加載到內存緩衝區中(使用File.ReadAllBytes()),然後從內存流中反序列化。這將允許您確定讀取的時間以及反序列化的時間。

如果反序列化需要花費很多時間,如果您有多個處理器,可以產生多個threds並行執行序列化。有了這樣一個系統,你可能會反序列化一個或多個表,同時爲另一個表加載數據。這種流水線方法可以使您的整個加載/反序列化時間幾乎與僅加載時一樣快。

+0

查找表的磁盤上的總數據少於100兆字節,所以我認爲可以排除數據傳輸限制。 – snazzer 2009-07-21 00:09:47

0

另一種選擇是把你的表到,好了,表:真正的數據庫表。即使像Access這樣的引擎也應該可以產生相當不錯的性能,因爲每個查詢都有一個明顯的索引。現在,應用程序只需在數據實際即將使用時讀入數據,即使這樣,它也會準確知道文件內部的位置。

這可能會使應用程序的實際性能稍微降低,因爲您必須爲每次計算都執行磁盤讀取。但是,這將使得應用程序的感知表現要好得多,因爲有從未了漫長的等待。不管你喜不喜歡,這種看法可能比現實更重要。

0

爲什麼拉鍊呢?

磁盤比RAM大。

直二進制讀應該是相當快的。