当我循环遍历文件A中的行时,我正在解析该行并将每个字符串(char*
)放入char**
中。
在一行的末尾,我运行一个过程,该过程包括打开文件B,使用fgets
、fseek
和fgetc
从该文件中抓取字符。然后关闭文件B。
我为每一行重复重新打开和重新关闭文件B。
我想知道的是:
1.使用malloc
和free
是否会对性能造成重大影响,因此我应该使用像myArray[NUM_STRINGS][MAX_STRING_WIDTH]
这样的静态对象,而不是动态char** myArray
?
1.打开和关闭文件B是否有很大的性能开销(从概念上讲,是数千次)?如果我的文件A被排序了,有没有办法让我使用fseek
在文件B中“向后”移动,重置我以前在文件B中的位置?
EDIT结果表明,双重方法大大减少了运行时间:
1.我的文件B实际上是24个文件中的一个。而不是打开同一个文件B1一千次,然后B2一千次,等等。我打开文件B1一次,关闭它,B2一次,关闭它,等等。这将数千个fopen
和fclose
操作减少到大约24个。
1.我使用rewind()
重置文件指针。
这产生了大约60倍的速度改进,这是绰绰有余的。谢谢你给我rewind()
。
8条答案
按热度按时间rmbxnbpk1#
如果动态数组随着时间的推移而增长,则在一些
realloc
s上存在复制成本。如果你使用“always double”的启发式算法,这将被分摊到O(n),所以它并不可怕。如果你提前知道了数组的大小,堆栈分配的数组仍然会更快。第二个问题是
rewind
。它必须比打开和关闭所有的时间更快,并让你做更少的资源管理。oxiaedzo2#
我想知道的是:
如果这两个问题的答案都是“是”,那就不要改变任何东西。
vyswwuz23#
打开和关闭具有可变开销,这取决于其他程序是否竞争该资源。
首先测量文件大小,然后使用它来提前计算数组大小,以进行一次大的堆分配。
你不会马上得到一个多维数组,但是一点指针运算就可以了。
你能不能不把位置信息缓存在另一个文件中,然后,而不是打开和关闭它,使用以前的查找索引作为偏移量?这取决于确切的逻辑。
5jdjgkvh4#
1.如果你的文件很大,磁盘I/O将比内存管理昂贵得多。在分析表明malloc/free性能是一个瓶颈之前就担心它是不成熟的优化。
1.频繁打开/关闭的开销在程序中可能很大,但实际的I/O开销可能更大,除非文件很小,在这种情况下,关闭和打开之间的缓冲区丢失可能会导致额外的磁盘I/O。是的,你可以使用ftell()来获取文件中的当前位置,然后使用SEEK_SET来查找。
ryhaxcpt5#
使用动态内存总是会影响性能。使用静态缓冲器将提供速度提升。
重新打开文件也会影响性能。您可以使用
fseek(pos, SEEK_SET)
将文件指针设置为文件中的任何位置,或使用fseek(offset, SEEK_CUR)
进行相对移动。重大的性能影响是相对的,您必须确定这对自己意味着什么。
dl5txlt96#
1.我认为最好分配您需要的实际空间,并且开销可能不会很大。这既避免了浪费空间,又避免了堆栈溢出
1.是的。虽然IO被缓存了,但你正在进行不必要的系统调用(打开和关闭)。使用fseek可能与
SEEK_CUR
或SEEK_SET
。gorkyyrv7#
在这两种情况下,都有 * 一些 * 性能损失,但其重要性取决于文件的大小和程序运行的上下文。
1.如果你实际上知道字符串的最大数量和最大宽度,这将快得多(但如果你使用的小于“max”,你可能会浪费很多内存)。中庸之道是做很多C++中的动态数组实现所做的事情:每当你必须realloc myArray时,分配你所需要的两倍的空间,只有当你用完空间时才重新realloc。这需要O(log n)的时间复杂度。
1.这可能是一个很大的性能打击。我强烈建议使用fseek,尽管具体细节取决于你的算法。
qco9c6ql8#
我经常发现
malloc
附带的直接内存管理和内存上的低级C处理程序超过了性能开销。除非这些内存区域将保持静态和未触及的时间量大于触及该内存的摊销时间,否则坚持使用静态数组可能更有益。最后,取决于你。