【问题标题】:C++ save and load huge vector<bool>C++ 保存和加载巨大的向量<bool>
【发布时间】:2013-07-11 23:20:18
【问题描述】:

我有一个巨大的vector&lt;vector&lt;bool&gt;&gt;(512x 44,000,000 位)。我需要 4-5 个小时来计算创建它,显然我想保存结果以免我再次重复这个过程。当我再次运行程序时,我要做的就是加载相同的向量(没有其他应用程序会使用此文件)。

我相信文本文件对于这么大的尺寸是不可能的。有没有一种简单(快速而肮脏)的方法来做到这一点?我不使用 Boost,这只是我的科学应用程序的一小部分,所以它必须是快速的。我还想过将其在线反转并将其存储在 Postgres DB 中(44000000 条记录,512 位数据),以便 DB 可以轻松处理它。我已经看到这样的答案需要 8bits > 1byte 然后保存,但是由于我有限的新手 C++ 经验,它们听起来太复杂了。有什么想法吗?

【问题讨论】:

  • 将原始位写入二进制文件并将它们读回是个好主意。如果不进行任何压缩,生成的文件将约为 2.6 GB,这应该不是问题。而且写和读应该不会占用太多代码,也不会太复杂。
  • 因为 ram 中有很多页面错误?
  • XML 和 SOAP 应该处理这个问题,或者 JSON 如果你很时髦的话......
  • @Kerrek:这么大的数据集的 ASCII 格式臃肿?你在开玩笑吧?

标签: c++ serialization vector


【解决方案1】:

您可以 8 位保存到单个字节中:

unsigned char saver(bool bits[])
{
   unsigned char output=0;
   for(int i=0;i<8;i++)
   {

           output=output|(bits[i]<<i); //probably faster than if(){output|=(1<<i);}
           //example: for the starting array 00000000
           //first iteration sets:           00000001 only if bits[0] is true
           //second sets:                    0000001x only if bits[1] is true
           //third sets:                     000001xx only third is true
           //fifth:                          00000xxx if fifth is false
           // x is the value before

   }
   return output;
}

您可以从单个字节加载 8 位:

void loader(unsigned char var, bool * bits)
{

   for(int i=0;i<8;i++)
   {

       bits[i] = var & (1 << i);
       // for example you loaded var as "200" which is 11001000 in binary
       // 11001000 --> zeroth iteration gets false
       // first gets false
       // second false
       // third gets true 
       //...
   }

}

1<<0 is 1  -----> 00000001
1<<1 is 2  -----> 00000010
1<<2 is 4  -----> 00000100
1<<3 is 8  -----> 00001000
1<<4 is 16  ----> 00010000
1<<5 is 32  ----> 00100000
1<<6 is 64  ----> 01000000
1<<7 is 128  ---> 10000000

编辑:使用 gpgpu,在 cpu 上花费 4-5 小时的令人尴尬的并行算法可以在 gpu 上缩短到 0.04 - 0.05 小时(甚至在多个 gpu 上不到一分钟)例如,上面的“保存器/加载器”函数是并行的。

【讨论】:

  • output |= (bits[i] &lt;&lt;i ); 更短并且摆脱了条件,因此可能也更快。
  • 好的,改成单任务了。谢谢。
【解决方案2】:

如前所述,这里 vec 是 bool 向量的向量,我们将所有位打包在子向量 8 x 8 中以字节为单位,并将这些 a 字节压入向量中。

 std::vector<unsigned char> buf;
 int cmp = 0;
 unsigned char output=0;
   FILE* of = fopen("out.bin")
  for_each ( auto& subvec in vec)
  {
       for_each ( auto b in subvec)
       {
            output=output | ((b ? 1 : 0) << cmp);
             cmp++;
            if(cmp==8)
             {
                 buf.push_back(output);
                 cmp = 0;
                 output = 0;
              }
          }
            fwrite(&buf[0], 1, buf.size(), of);
            buf.clear();
       }

         fclose(of);

【讨论】:

  • 对于这个问题大小,不建议在单个块中处理整个缓冲区。
  • 是的,但可能对 512 个子向量中的每一个都进行(每个向量 5Mb)。
  • 我同意将在循环中调用异步写入以刷新 1024 字节的块。
【解决方案3】:

我见过这样的答案需要 8bits > 1byte 然后保存,但是以我有限的新手 C++ 经验,它们听起来太复杂了。有什么想法吗?

如果您要经常阅读该文件,这将是学习按位运算的好时机。每个布尔使用一位将是大小的 1/8。这将节省大量内存和 I/O。

因此将其保存为每个布尔值一位,然后将其分成块和/或使用映射内存读取它(例如mmap)。你可以把它放在一个可用的接口后面,所以你只需要实现一次,并在需要读取值时抽象出序列化格式。

【讨论】:

    猜你喜欢
    • 2020-03-15
    • 2018-12-13
    • 1970-01-01
    • 2012-09-04
    • 2012-04-28
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多