Linux讀取
讀取 /usr/share/dict/words
的副本比文件本身慢 10 倍
我正在嘗試用 C 語言實現字典,發現
/usr/share/dict/words
它是一個非常好的測試文件。無論出於何種原因,我想將 words 文件的副本複製到我的工作目錄中,但令我驚訝的是,該程序在讀取文件時明顯變慢了。什麼可以解釋這種行為?這兩個文件是相同的。如果我不得不猜測,它可能
/usr/share/dict/words
已經緩沖在記憶體中,因為它是一個經常使用的文件?#define _GNU_SOURCE #include <assert.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #define GET_TIME(now) \ do { \ struct timeval t; \ gettimeofday(&t, NULL); \ now = t.tv_sec + t.tv_usec / 1000000.0; \ } while (0) #define REPORT(msg, time) \ do { \ printf("%-10s- %f\n", msg, time); \ } while (0) #define SHOW_INVALID 0 struct dict { int n; char *data[110000]; }; int valid_word(char *input) { for (int i = 0; input[i]; i++) { if (!islower(input[i]) && !(input[i] == '\n')) { return 0; } } return 1; } struct dict *get_dict(char *file) { struct dict *dict = calloc(1, sizeof(struct dict)); FILE *fp = fopen(file, "r"); char input[128]; while (fgets(input, 128, fp)) { if (valid_word(input)) { dict->data[dict->n++] = strdup(input); } else { #if SHOW_INVALID == 1 printf("Skipping invalid word %s", input); #endif } } fclose(fp); return dict; } void destroy_dict(struct dict *dict) { for (int i = 0; i < dict->n; i++) { free(dict->data[i]); } free(dict); } int search(struct dict *dict, int l, int r, char *word) { if (l > r) return -1; int mid = l + (r - l) / 2; if (!strcmp(dict->data[mid], word)) return mid; if (strcmp(dict->data[mid], word) > 0) return search(dict, l, mid - 1, word); return search(dict, mid + 1, r, word); } int match(struct dict *dict, char *word) { return search(dict, 0, dict->n - 1, word); } void test(struct dict *dict, char *file) { FILE *fp = fopen(file, "r"); char input[128]; while (fgets(input, 128, fp)) { if (valid_word(input)) { assert(match(dict, input) != -1); } else { assert(match(dict, input) == -1); } } fclose(fp); } int main(void) { double init, start, end; GET_TIME(init); GET_TIME(start); struct dict *dict = get_dict("words"); GET_TIME(end); REPORT("setup", end - start); GET_TIME(start); test(dict, "words"); GET_TIME(end); REPORT("words", end - start); GET_TIME(start); test(dict, "words_random"); GET_TIME(end); REPORT("randwords", end - start); GET_TIME(start); destroy_dict(dict); GET_TIME(end); REPORT("teardown", end - start); puts(""); REPORT("total", end - init); return 0; }
正如@Vilinkameni 所指出的,如果正在訪問的文件位於不同的物理設備或文件系統類型上,則 GNU/Linux 中的 I/O 性能可能會有所不同。
在我的例子中,WSL2 使用了一個虛擬硬碟,但我的工作目錄(WSL
cd
的目標)實際上在我的C:/
驅動器上。因此,在訪問/usr/share/dict/words
文件時,我仍保留在 WSL2 VHD 中,但如果我將文件複製到我的C:/
驅動器,那就是性能下降的地方——因為它必須讀取另一個“文件系統”上的文件。我通過將我的程序移動到
/usr/share/dict/
,在那裡創建文件的副本來測試這一點,words
現在性能是相同的。