对于C分配,我应该在大文本文件中拆分单词并逐个处理。基本上,单词是字母表的任何线性序列。因为,这将是我的程序的瓶颈,我想尽可能快地完成这个过程。
我的想法是使用扫描函数格式说明符([a-zA-z])将文件中的单词扫描到字符串缓冲区中。如果缓冲区已满,我检查文件中是否有更多字母(基于文件指针所在的位置)。如果有,那么我增加缓冲区大小并继续将更多字母复制到缓冲区,直到我点击非字母表。
问题是我是否使用fscanf或sscanf(将整个文件复制到字符串中)。是一个比另一个更快还是有更好的替代我的想法?
答案 0 :(得分:2)
你的问题几乎不是主题,因为它需要基于意见的答案。
了解一种方法与另一种方法的比较速度的唯一方法是同时尝试这两种方法并测量生成的可执行文件在实际数据上的性能。
由于普通电脑具有当今的计算能力,因此需要非常大文件来衡量实际的性能差异。
所以继续实施你的想法。您似乎对潜在的性能瓶颈有了很好的理解,将这些想法转化为实际的C代码。为这个问题提供2个不同但正确的程序以及性能分析应该会给你一个A +。作为雇主,我在测试中重视这种方法。
PS:恕我直言,大部分时间都将用于从文件系统获取数据。如果文件大于可用内存,那应该是你的瓶颈。如果文件适合操作系统文件系统缓存,后续基准测试应该比第一个更好...如果您被允许编写特定于系统的代码,请尝试使用mmap
和简单for
循环以及通过mmapped char
数组上的查找表进行显式测试。
答案 1 :(得分:2)
正如Heto在评论中指出的,这里的主要瓶颈可能是从磁盘读取文件,而不是您决定使用的scanf
函数变体。
如果您真的想加速应用程序,则应尝试构建管道。在您现在描述应用程序时,您基本上分两个阶段工作:将文件读入缓冲区,并从缓冲区中解析单词。
如果您决定将整个文件读入字符串,然后在字符串上使用sscanf
,那么活动可能会是什么样子:
reading: ████████████████
parsing: ████████████████
如果您直接在文件上使用fscanf
,您会得到一些不同的东西,因为您不断在阅读和解析之间切换:
reading: █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
parsing: █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
在这两种情况下,你最终花费的时间相同。
但是,如果您可以异步执行文件i / o ,则可以将等待磁盘数据的时间与计算时间重叠。理想情况下,您最终得到的结论是:
reading: ████████████████
parsing: ████████████████
我的图表可能不那么准确(我们已经指出,指出解析应该比i / o花费的时间少得多,所以这两个柱子的长度确实不应该相同) - 但是你应该这样做得到一般的想法。如果您可以设置一个从处理中异步读取数据的管道,那么您可以通过重叠通信(从磁盘读取)和计算(解析)来获得大的加速。
你可以使用POSIX asynchronous I/O (aio)来实现这样的异步管道,或者只使用两个线程进行简单的生产者/消费者设置(其中一个从文件中读取,另一个从解析中读取)。
老实说,除非您正在处理大量文本文件,否则您可能几乎无法衡量任何可能的方法之间的速度差异选择...
这种流水线方法更适用于您执行更多计算密集型操作(不仅仅是扫描字符),并且您的通信延迟更高(例如,当数据来自网络而不是来自本地磁盘时) 。但是,探索不同的选择仍然是一个很好的练习。毕竟,无论如何,这个任务都是设计的 - 重点是学习一些有用的东西,你可以在以后的某个实际项目中使用它,对吗?
另外,使用scanf
中的任何一个都可能比仅仅循环缓冲区以提取字符串[A-Za-z]
更慢。这是因为,对于任何scanf
函数,代码首先需要解析您的格式字符串以找出您要查找的内容,然后实际解析输入。有时编译器可以做一些聪明的事情 - 比如gcc通常如何将printf
没有格式说明符改为puts
- 但我不认为scanf
有类似的优化和朋友一起,特别是如果您使用%[A-Za-z]
之类的特殊内容而非%d
等标准格式说明符。