[英]The speed of fscanf and sscanf
對於C作業,我應該將一個大文本文件中的單詞分解並一個一個處理。 基本上,一個單詞是字母的任何線性序列。 因為,這將是我的程序的瓶頸,所以我想讓這個過程盡可能快。
我的想法是使用掃描函數格式說明符 ([a-zA-z]) 將文件中的單詞掃描到字符串緩沖區中。 如果緩沖區已滿,我會檢查文件中是否有更多字母(基於文件指針所在的位置)。 如果有,那么我增加緩沖區大小並繼續將更多字母復制到緩沖區中,直到遇到非字母。
問題是我是使用 fscanf 還是 sscanf(將整個文件復制到一個字符串中)。 一個比另一個更快還是有更好的替代我的想法?
您的問題幾乎偏離主題,因為它需要基於意見的答案。
了解一種方法與另一種方法相比有多快的唯一方法是嘗試兩種方法並測量生成的可執行文件在真實數據上的性能。
以當今普通 PC 中可用的計算能力,需要一個非常大的文件來衡量實際性能差異。
因此,請繼續實施您的想法。 您似乎對潛在的性能瓶頸有很好的了解,將這些想法轉化為實際的 C 代碼。 為這個問題提供 2 個不同但正確的程序以及性能分析應該會讓你獲得 A+。 作為雇主,我在測試中重視這種方法。
PS:恕我直言,大部分時間將用於從文件系統獲取數據。 如果文件大於可用內存,那應該是你的瓶頸。 如果該文件可以放入操作系統文件系統緩存中,那么后續的基准測試應該會為您提供比第一個更好的性能...
如果允許您編寫特定於系統的代碼,請嘗試使用mmap
和簡單的for
循環,通過在 mmapped char
數組上查找表進行顯式測試。
正如 Heto 在評論中指出的那樣,這里的主要瓶頸可能是從磁盤讀取文件,而不是您決定使用的任何scanf
函數變體。
如果你真的想加速你的應用程序,你應該嘗試構建一個管道。 當您現在描述應用程序時,您基本上分兩個階段工作:將文件讀入緩沖區,並從緩沖區解析單詞。
如果您決定將整個文件讀入一個字符串,然后在該字符串上使用sscanf
,則活動可能如下所示:
reading: ████████████████
parsing: ████████████████
如果您直接在文件上使用fscanf
您會得到一些不同的東西,因為您經常在讀取和解析之間切換:
reading: █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
parsing: █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
在這兩種情況下,您最終花費的時間大致相同。
但是,如果您可以異步執行文件 i/o,那么您可以將等待磁盤數據的時間與用於計算的時間重疊。 理想情況下,你最終會得到這樣的結果:
reading: ████████████████
parsing: ████████████████
我的圖表可能不那么准確(我們已經指出,解析應該比 i/o 花費的時間少得多,所以兩個條形真的不應該是相同的長度)——但你應該得到大致的想法。 如果您可以設置一個管道,從處理中異步讀取數據,那么您可以通過重疊通信(從磁盤讀取)和計算(解析)來獲得很大的加速。
您可以使用POSIX 異步 I/O (aio)來實現這樣的異步管道,或者只是使用兩個線程進行簡單的生產者/消費者設置(其中一個從文件中讀取,另一個進行解析)。
老實說,除非您正在處理大量文本文件,否則您可能幾乎無法測量您可能選擇的任何可能方法之間的速度差異......
當您執行計算密集度更高的操作(不僅僅是掃描字符)並且您的通信延遲更高(例如當數據來自網絡而不是來自本地磁盤時)時,這種流水線方法更適用。 但是,探索不同的選項仍然是一個很好的練習。 畢竟,無論如何,這個作業都是人為設計的——重點是學習一些有用的東西,你以后可能會在真正的項目中使用它,對吧?
另請注意,使用任何scanf
可能比僅循環緩沖區以提取字符串[A-Za-z]
慢。 這是因為,對於任何scanf
函數,代碼首先需要解析您的格式字符串以找出您要查找的內容,然后實際解析輸入。 有時,編譯器可以做聰明事般GCC通常是如何改變一個printf
無格式說明成puts
來代替,但我不認為有這樣的優化scanf
和朋友,特別是如果你使用一些特別的東西就像%[A-Za-z]
而不是像%d
這樣的標准格式說明符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.