0

我正在尝试使用令人讨厌的大型 xml 和文本文档:~40GBs。我在 Windows 7 上使用 Visual Studio 2012。

我将使用“Xerces”从 xml 中获取页眉/“页脚标签”。

我想映射文件的一个区域,比如说.. 60-120MBs。

将地图分成(3 * 个处理器/核心)相等的部分。将每个部分设置为缓冲区并将缓冲区加载到数组中。

然后在新线程中使用 (#processors/cores) while statments,我将在浏览缓冲区数组时同步计算字符/行/xml 周期。当一个缓冲区完成时,该进程将跳转到下一个“可用”缓冲区,并且完成的缓冲区将从内存中删除。最后,我会将总结果添加到项目日志中。

之后,我将参考日志,按字符数/大小(或其他选项)将文件拆分到最近的行或循环,并将页眉和“页脚标签”放入所有拆分中。

我这样做是为了可以通过具有多台计算机的网络将大量数据导入 MySQL 服务器。

我的问题是,如何使用新线程创建缓冲区数组和文件映射?

我可以用吗 :

赢得创建文件

赢得 CreateFileMapping

赢得 MapViewOfFile

使用标准 ifstream 操作和 char 缓冲区还是应该选择其他东西?

进一步澄清:我的想法是,如果我可以让硬盘驱动器从一个地方和一个方向将文件流式传输到内存中,我可以利用机器的全部处理能力来咀嚼单独但相等的缓冲区。

〜味道:这有点像一个牧羊人试图从一个带有 3-6 个大桶的大箱子里舀出食物,只有两条手臂用于需要留在围栏区域内的 X 只羊。但它们都以光速运动。

一些想法或建议可能会对我有所帮助。任何想法都是最受欢迎的。谢谢。

while(getline(my_file, myStr))
{
   characterCount += myStr.length();

   lineCount++;


   if(my_file.eof()){

      break;

   }
}

这是测试运行时唯一的代码。2小时30+分钟。在具有 2GB RAM 的双核 1.6Mhz 笔记本电脑上运行程序的总处理器为 45-50%。现在加载的大部分 RAM 是 600+MB,来自在 Firefox 中打开的约 50 个选项卡,Visual Studio 为 60MB,然后是等。

重要提示:在测试过程中,运行代码的程序,它只是一个窗口和一个对话框,似乎转储了它自己的工作和私有内存集,下降到像 300K ish,并且没有响应的长度考试。我确定我需要为 while 语句创建另一个线程。但这意味着没有文件被读入缓冲区。CPU 在整个运行过程中都在努力跟上硬盘驱动器的最小努力。

PS 进一步证明 CPU 瓶颈。通过我的无线网络将整个文件传输到另一台计算机可能需要 20 分钟。其中包括读取进程和套接字捕获以在另一台计算机上写入进程。

更新

我用这个可爱的小东西从之前的测试时间缩短到大约 15-20 分钟,这与 Mats Petersson 所说的一致。

while (my_file.read( &bufferOne[0], bufferOne.size() ))

{

int cc = my_file.gcount();

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

    if (bufferOne[i] == '\n')
        lineCount++;

    characterCount++;

}

currentPercent = characterCount/onePercent;

SendMessage(GetDlgItem(hDlg, IDC_GENPROGRESS), PBM_SETPOS, currentPercent, 0);

}

当然,这是一个单循环,它实际上比之前的测试表现得更合适。该测试比上面显示的使用 Getline 的紧密循环快约 800%。我将此循环的缓冲区设置为 20MB。我从: SOF - Fastest Example中提取了这段代码

但...

我想指出的是,在资源监视器和任务管理器中轮询进程时,它清楚地显示第一个核心的使用率为 75-90%,第二个核心的使用率为 25-50%(对于我打开的一些小背景内容来说,这是相当标准的) ), 硬盘在.. 等待它... 50%。一些 100% 的磁盘时间峰值,但也有一些 25% 的低点。所有这些基本上意味着在两个不同线程之间拆分缓冲区处理很可能是一个好处。它将使用所有系统资源,但是..这就是我想要的。当我有工作原型时,我将在今天晚些时候更新。

主要更新:经过大量学习,我终于完成了我的项目。不需要文件映射。只有一堆矢量字符。我已经成功构建了一个动态执行的文件流线和字符计数器。好消息是,从之前的 10-15 分钟标记到 5.8GB 文件的 ~3-4 分钟,BOOYA!~

4

1 回答 1

1

非常简短的回答:是的,您可以使用这些功能。

对于读取数据,将文件内容映射到内存可能是最有效的方法,因为它不必将内存复制到应用程序的缓冲区中,只需将其直接读取到它应该去的地方。所以,只要你有足够的可用地址空间就没有问题 - 64 位机器当然应该有足够的,在 32 位系统中它可能是一种稀缺资源 - 但对于几百 MB 的部分,它应该不是一个大问题。

但是,使用多个线程,我一点也不相信。我有一个公平的想法,即读取一个非常大的文件的多个部分会适得其反。这将增加磁盘上的磁头移动量,这是传输速率的很大一部分。对于“普通”系统,您可以指望大约 50-100MB/s 的传输速率。如果系统有某种raid控制器或类似的,可能会翻倍——非常奇特的raid控制器可能会达到三倍。

所以读取 40GB 需要大约 3-15 分钟。

CPU 可能不会很忙,运行多个线程很可能会降低系统的整体性能。

您可能希望保留一个用于读取的线程和一个用于写入的线程,并且只有在您拥有足够数量的数据时才实际写出数据,以避免磁盘上读/写磁头的不必要移动。

于 2013-03-12T16:14:25.197 回答