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 压缩导致速度变慢,但从序列化/反序列化例程中删除它只需要几百毫秒。

任何人都可以建议在应用程序初始启动时加快这些查找表的加载时间的方法吗?

4

5 回答 5

2

首先,在后台线程中反序列化将防止应用程序在发生这种情况时“挂起”。仅此一项就足以解决您的问题。

但是,序列化和反序列化(尤其是大型字典)通常会非常缓慢。根据数据结构,编写自己的序列化代码可以显着加快速度,尤其是在数据结构中没有共享引用的情况下。

话虽如此,根据其使用模式,数据库可能是更好的方法。您总是可以制作更面向数据库的东西,并以惰性方式从数据库构建查找表(即:查找是在 LUT 中查找,但如果查找不存在,则从数据库加载并保存它在表中)。这将使启动瞬间完成(至少在 LUT 方面),并且可能仍然保持查找相当快速。

于 2009-07-21T00:02:10.740 回答
0

我想显而易见的建议是将它们加载到后台。一旦应用程序启动,用户打开了他们的项目,并选择了他们想要的任何操作,那么等待的 15 秒就不会太多了。

于 2009-07-20T23:53:37.167 回答
0

我们在这里谈论多少数据?根据我的经验,将 1 GB 从磁盘读取到内存大约需要 20 秒。因此,如果您的阅读量超过 0.5GB,那么您几乎肯定会遇到硬件限制。

如果数据传输率不是问题,那么实际的反序列化需要时间。如果您有足够的内存,您可以将所有表加载到内存缓冲区(使用File.ReadAllBytes()),然后从内存流中反序列化。这将允许您确定读取花费了多少时间,以及反序列化花费了多少时间。

如果反序列化需要大量时间,如果您有多个处理器,则可以生成多个线程来并行执行序列化。使用这样的系统,您可能会反序列化一个或多个表,同时为另一个表加载数据。这种流水线方法可以使您的整个加载/反序列化时间几乎与仅加载一样快。

于 2009-07-21T00:05:25.617 回答
0

另一种选择是将您的表放入表中:真正的数据库表。即使是像 Access 这样的引擎也应该产生相当好的性能,因为每个查询都有一个明显的索引。现在应用程序只需要在实际使用数据时读取数据,即便如此,它也会知道在文件内部的确切位置。

这可能会降低应用程序的实际性能,因为您必须为每次计算执行磁盘读取。但这会使应用程序的感知性能更好,因为永远不会等待很长时间。而且,不管你喜不喜欢,感觉可能比现实更重要。

于 2009-07-21T00:08:21.973 回答
0

为什么要压缩它们?

磁盘比 RAM 大。

直接二进制读取应该很快。

于 2009-07-21T00:26:56.167 回答