
我正在嘗試用 C 語言實作字典,發現/usr/share/dict/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;
}
答案1
正如 @Vilinkameni 指出的,如果正在存取的文件位於不同的實體裝置或檔案系統類型上,GNU/Linux 中的 I/O 效能可能會有所不同。
就我而言,WSL2 使用虛擬硬碟,但我的工作目錄(WSL 的目標目錄cd
)實際上位於我的C:/
磁碟機上。因此,在存取/usr/share/dict/words
檔案時,我仍保留在 WSL2 VHD 中,但如果我將檔案複製到我的C:/
磁碟機,這就是效能受到影響的地方,因為它必須讀取另一個「檔案系統」上的檔案。
我通過將程式移動到/usr/share/dict/
並在那裡創建文件的副本來測試這一點words
,現在性能是相同的。