3

我正在处理一个回调函数,其中基于回调中的数据,我想写入不同的文件。

例如,在一次通话中,我可能想写入 january.csv,而在另一次使用不同数据的通话中,可能改为 july.csv。没有预先确定的顺序,每个回调可能是任何月份,我无法提前知道。january.csv(实际上是所有月份)将被多次写入。

这些回调发生得非常快,所以我需要这段代码尽可能高效。

我会采取的天真的方法是每次都使用以下代码:

ofstream fout;
fout.open(month_string);
fout<<data_string<<endl;
fout.close();

问题是这似乎不是很有效,因为我不断打开/关闭 month.csv 文件。有没有更快的方法,我可以说保持 january.csv、february.csv 等一直打开以加快速度?

编辑:我在 Linux 上写信给 /dev/shm,所以 I/O 延迟并不是真正的问题。

4

3 回答 3

2

您希望减少 I/O 调用的数量,同时在调用它们时充分利用它们。

例如,缓存数据并将更大的块写入文件。您可以有另一个线程负责定期将缓冲区刷新到文件中。

效率低下的原因有两个:等待硬盘驱动器初始化(加快速度),第二个是定位文件和要写入的空扇区。无论您正在写入的数据量如何,都会发生这种开销. 数据块越大,有效写入所花费的时间就越多(当盘片旋转时)。闪存/拇指驱动器也是如此;拇指驱动器有开销(解锁、擦除等)。所以目标是通过大块写入来减少开销。

您可能要考虑使用数据库: 评估对数据库的需求。

于 2013-03-19T15:16:19.417 回答
0

I doubt most systems will allow you to have ~10K files open at once, which more or less rules out just opening all the files and writing to them as needed.

As such, you probably just about need to create some sort of proxy-ish object to buffer data for each file, and when a buffer exceeds some given size, open the file, write the data to disk, and close it again.

I can see two fairly simple approaches to this. One would be to write most of the code yourself, using a stringstream as the buffer. The client streams to your object, which just passing through to the stringstream. Then you check if the stringstream exceeds some length, and if so, you write the content to disk and empty the stringstream.

The other approach would be to write your own file buffer object that implements sync to open the file, write the data, and close the file again (where it would normally leave the file open all the time).

Then you'd store those in a std::map (or std::unordered_map) to let you do a lookup from the file name to the matching proxy object.

于 2013-03-19T15:24:16.307 回答
0

我不认为一遍又一遍地打开和关闭同一个文件会那么昂贵。操作系统通常设计为通过在内存中缓存部分 FS 元数据来处理该用例。成本主要是系统调用的上下文切换。另一方面,对 10k 文件执行此操作可能会耗尽操作系统缓存能力。

您可以通过将所有带有目标注释的输出按顺序写入单个文件中以形成日志,从而减轻您这边的一些 FS 工作。然后另一个程序(FS suppleant)将负责打开该日志,缓冲写入命令(按文件分组),然后在缓冲区达到某个阈值时将它们刷新到磁盘。您必须在日志中将执行的命令标记为已提交,以便在 suppleant 中断并且必须恢复的情况下,它会知道还需要做什么。


更新:

可以调整文件系统以支持同时打开和缓存 10000 个文件,并让它处理调度命令的问题(这就是 FS 的用途)。

您的问题是为您的用例实际选择正确的文件系统。我建议用不同的 FS 进行测试,看看哪一个表现最好。

剩下的唯一部分是让您的程序用于std::map 将文件名与其描述符相关联(微不足道)。

请参阅 SO 以调整linux max open files,或者如果您在特定的 FS 上找不到问题,请询问有关该主题的问题。

于 2013-03-19T15:24:23.147 回答