readahead系统调用及示例

readahead 函数详解

  1. 函数介绍

readahead 是一个Linux系统调用,用于预读文件数据到内核页面缓存中。它允许应用程序提示内核提前读取指定文件区域的数据,从而提高后续读取操作的性能。这个函数特别适用于顺序访问大文件的场景,可以减少I/O等待时间。

  1. 函数原型
1
2
3
4
#define _GNU_SOURCE
#include <fcntl.h>
ssize_t readahead(int fd, off64_t offset, size_t count);

  1. 功能

readahead 向内核发出预读提示,建议内核提前将文件中从 offset 开始的 count 字节数据读入页面缓存。这是一个非阻塞操作,不会立即读取数据,而是让内核在适当的时候进行预读。

  1. 参数
  • int fd: 文件描述符,必须是已打开的文件(通常需要支持预读的文件系统)

  • off64_t offset: 文件中的偏移量,指定预读开始位置

  • size_t count: 预读的字节数,内核可能根据策略调整实际预读量

  1. 返回值
  • 成功: 返回0,表示预读请求已提交

  • 失败: 返回-1,并设置errno

  1. 相似函数,或关联函数
  • posix_fadvise: 文件访问建议接口,包含预读建议

  • mmap: 内存映射文件,可以配合MAP_POPULATE使用

  • read: 基本读取函数

  • lseek: 文件定位函数

  1. 示例代码

示例1:基础预读示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>

/**
* 创建大文件用于测试
*/
int create_test_file(const char *filename, size_t size) {
int fd;
char *buffer;
size_t chunk_size = 1024 * 1024; // 1MB chunks
size_t written = 0;

fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
return -1;
}

buffer = malloc(chunk_size);
if (!buffer) {
perror("分配缓冲区失败");
close(fd);
return -1;
}

// 填充测试数据
for (size_t i = 0; i < chunk_size; i++) {
buffer&#91;i] = 'A' + (i % 26);
}

printf("正在创建 %zu MB 的测试文件...\n", size / (1024 * 1024));

while (written < size) {
size_t to_write = (size - written < chunk_size) ? size - written : chunk_size;
ssize_t result = write(fd, buffer, to_write);
if (result == -1) {
perror("写入文件失败");
free(buffer);
close(fd);
return -1;
}
written += result;
}

free(buffer);
close(fd);
printf("测试文件创建完成\n");
return 0;
}

/**
* 测量读取时间
*/
double time_read_operation(int fd, void *buffer, size_t size) {
struct timespec start, end;
ssize_t total_read = 0;
off_t offset = 0;

clock_gettime(CLOCK_MONOTONIC, &start);

while (total_read < (ssize_t)size) {
ssize_t to_read = (size - total_read < 1024 * 1024) ? size - total_read : 1024 * 1024;
ssize_t result = pread(fd, (char*)buffer + total_read, to_read, offset);
if (result == -1) {
perror("读取文件失败");
return -1;
}
if (result == 0) break; // 文件结束

total_read += result;
offset += result;
}

clock_gettime(CLOCK_MONOTONIC, &end);

return (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
}

/**
* 演示readahead的基本使用
*/
int demo_readahead_basic() {
const char *filename = "test_readahead.dat";
const size_t file_size = 50 * 1024 * 1024; // 50MB
int fd;
char *buffer;
double time_without, time_with;

printf("=== readahead 基本使用示例 ===\n");

// 创建测试文件
if (create_test_file(filename, file_size) != 0) {
return -1;
}

// 分配读取缓冲区
buffer = malloc(file_size);
if (!buffer) {
perror("分配读取缓冲区失败");
unlink(filename);
return -1;
}

// 测试不使用readahead的读取性能
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
free(buffer);
unlink(filename);
return -1;
}

printf("第一次读取(无预读)...\n");
time_without = time_read_operation(fd, buffer, file_size);
if (time_without > 0) {
printf("无预读读取时间: %.3f 秒\n", time_without);
}

close(fd);

// 测试使用readahead的读取性能
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
free(buffer);
unlink(filename);
return -1;
}

// 使用readahead预读整个文件
printf("执行预读操作...\n");
if (readahead(fd, 0, file_size) == 0) {
printf("预读请求提交成功\n");
} else {
printf("预读请求失败: %s\n", strerror(errno));
}

// 等待一小段时间让预读完成
sleep(1);

printf("第二次读取(有预读)...\n");
time_with = time_read_operation(fd, buffer, file_size);
if (time_with > 0) {
printf("有预读读取时间: %.3f 秒\n", time_with);
if (time_without > 0) {
printf("性能提升: %.1f%%\n",
(time_without - time_with) / time_without * 100);
}
}

close(fd);
free(buffer);
unlink(filename);

return 0;
}

int main() {
return demo_readahead_basic();
}

示例2:分段预读示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>

/**
* 演示分段预读的使用
*/
int demo_readahead_segmented() {
const char *filename = "segmented_test.dat";
const size_t file_size = 100 * 1024 * 1024; // 100MB
const size_t segment_size = 10 * 1024 * 1024; // 10MB per segment
int fd;
char *buffer;
struct timespec start, end;
double total_time = 0;

printf("=== readahead 分段预读示例 ===\n");

// 创建测试文件
int test_fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (test_fd == -1) {
perror("创建测试文件失败");
return -1;
}

buffer = malloc(segment_size);
if (!buffer) {
perror("分配缓冲区失败");
close(test_fd);
unlink(filename);
return -1;
}

// 填充测试数据
for (size_t i = 0; i < segment_size; i++) {
buffer&#91;i] = 'A' + (i % 26);
}

// 写入文件数据
for (size_t offset = 0; offset < file_size; offset += segment_size) {
write(test_fd, buffer, segment_size);
}

close(test_fd);
printf("创建了 %zu MB 的测试文件\n", file_size / (1024 * 1024));

// 打开文件进行测试
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
free(buffer);
unlink(filename);
return -1;
}

printf("开始分段读取测试...\n");

// 分段预读和读取
for (size_t offset = 0; offset < file_size; offset += segment_size) {
printf("处理段 %zu/%zu MB\n",
(offset + segment_size) / (1024 * 1024),
file_size / (1024 * 1024));

// 预读当前段
clock_gettime(CLOCK_MONOTONIC, &start);
if (readahead(fd, offset, segment_size) == 0) {
// printf(" 预读段 %zu 完成\n", offset / segment_size);
} else {
printf(" 预读段 %zu 失败: %s\n", offset / segment_size, strerror(errno));
}

// 等待预读完成(实际应用中可能不需要)
usleep(100000); // 100ms

// 读取当前段
ssize_t bytes_read = pread(fd, buffer, segment_size, offset);
if (bytes_read == -1) {
perror("读取段失败");
break;
}

clock_gettime(CLOCK_MONOTONIC, &end);
double segment_time = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
total_time += segment_time;

printf(" 段处理时间: %.3f 秒\n", segment_time);
}

printf("\n总处理时间: %.3f 秒\n", total_time);
printf("平均段处理时间: %.3f 秒\n", total_time / (file_size / segment_size));

close(fd);
free(buffer);
unlink(filename);

return 0;
}

int main() {
return demo_readahead_segmented();
}

示例3:与posix_fadvise对比示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>

/**
* 创建测试文件
*/
int create_large_file(const char *filename, size_t size) {
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建文件失败");
return -1;
}

char *buffer = malloc(1024 * 1024);
if (!buffer) {
perror("分配缓冲区失败");
close(fd);
return -1;
}

// 填充数据
for (int i = 0; i < 1024 * 1024; i++) {
buffer&#91;i] = 'A' + (i % 26);
}

size_t written = 0;
while (written < size) {
size_t to_write = (size - written < 1024 * 1024) ? size - written : 1024 * 1024;
ssize_t result = write(fd, buffer, to_write);
if (result == -1) {
perror("写入文件失败");
free(buffer);
close(fd);
return -1;
}
written += result;
}

free(buffer);
close(fd);
return 0;
}

/**
* 使用readahead进行预读
*/
int test_readahead_method(const char *filename) {
int fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
return -1;
}

struct stat sb;
if (fstat(fd, &sb) == -1) {
perror("获取文件状态失败");
close(fd);
return -1;
}

// 使用readahead预读
if (readahead(fd, 0, sb.st_size) == 0) {
printf("使用readahead预读成功\n");
} else {
printf("使用readahead预读失败: %s\n", strerror(errno));
}

close(fd);
return 0;
}

/**
* 使用posix_fadvise进行预读
*/
int test_fadvise_method(const char *filename) {
int fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
return -1;
}

struct stat sb;
if (fstat(fd, &sb) == -1) {
perror("获取文件状态失败");
close(fd);
return -1;
}

// 使用posix_fadvise预读
if (posix_fadvise(fd, 0, sb.st_size, POSIX_FADV_WILLNEED) == 0) {
printf("使用posix_fadvise预读成功\n");
} else {
printf("使用posix_fadvise预读失败: %s\n", strerror(errno));
}

close(fd);
return 0;
}

/**
* 演示readahead与posix_fadvise的对比
*/
int demo_readahead_vs_fadvise() {
const char *filename = "comparison_test.dat";
const size_t file_size = 50 * 1024 * 1024; // 50MB

printf("=== readahead vs posix_fadvise 对比示例 ===\n");

// 创建测试文件
if (create_large_file(filename, file_size) != 0) {
return -1;
}

printf("创建了 %zu MB 的测试文件\n", file_size / (1024 * 1024));

printf("\n1. 测试readahead方法:\n");
test_readahead_method(filename);

printf("\n2. 测试posix_fadvise方法:\n");
test_fadvise_method(filename);

printf("\n3. 功能对比:\n");
printf(" readahead:\n");
printf(" - 专门的预读系统调用\n");
printf(" - 直接控制预读字节数\n");
printf(" - 更精确的控制\n");
printf(" posix_fadvise:\n");
printf(" - 通用的文件访问建议接口\n");
printf(" - 支持多种访问模式\n");
printf(" - 更好的可移植性\n");

unlink(filename);
return 0;
}

int main() {
return demo_readahead_vs_fadvise();
}

示例4:实际应用场景示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>

/**
* 模拟视频播放器的预读策略
*/
typedef struct {
int fd;
off_t file_size;
off_t current_pos;
size_t buffer_size;
} video_player_t;

/**
* 初始化视频播放器
*/
int video_player_init(video_player_t *player, const char *filename) {
player->fd = open(filename, O_RDONLY);
if (player->fd == -1) {
perror("打开视频文件失败");
return -1;
}

struct stat sb;
if (fstat(player->fd, &sb) == -1) {
perror("获取文件状态失败");
close(player->fd);
return -1;
}

player->file_size = sb.st_size;
player->current_pos = 0;
player->buffer_size = 2 * 1024 * 1024; // 2MB缓冲区

printf("视频文件大小: %.2f MB\n", player->file_size / (1024.0 * 1024.0));

return 0;
}

/**
* 播放视频(模拟)
*/
int video_player_play(video_player_t *player, int use_readahead) {
char *buffer = malloc(player->buffer_size);
if (!buffer) {
perror("分配播放缓冲区失败");
return -1;
}

printf("开始播放视频%s预读...\n", use_readahead ? "(使用" : "(不使用");

struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);

while (player->current_pos < player->file_size) {
// 根据播放位置决定是否预读
if (use_readahead && player->current_pos + player->buffer_size < player->file_size) {
// 预读下一缓冲区的数据
off_t ahead_pos = player->current_pos + player->buffer_size;
size_t ahead_size = (player->file_size - ahead_pos > player->buffer_size) ?
player->buffer_size : player->file_size - ahead_pos;

if (readahead(player->fd, ahead_pos, ahead_size) == 0) {
// printf("预读位置 %ld, 大小 %zu\n", ahead_pos, ahead_size);
}
}

// 读取当前缓冲区数据
ssize_t bytes_read = pread(player->fd, buffer, player->buffer_size, player->current_pos);
if (bytes_read <= 0) {
if (bytes_read == -1) {
perror("读取视频数据失败");
}
break;
}

// 模拟解码和播放处理
usleep(50000); // 50ms处理时间

player->current_pos += bytes_read;

if (player->current_pos % (10 * 1024 * 1024) == 0) {
printf("已播放 %.2f MB\n", player->current_pos / (1024.0 * 1024.0));
}
}

clock_gettime(CLOCK_MONOTONIC, &end);
double play_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;

printf("播放完成,总时间: %.3f 秒\n", play_time);

free(buffer);
return 0;
}

/**
* 清理视频播放器
*/
void video_player_cleanup(video_player_t *player) {
if (player->fd != -1) {
close(player->fd);
player->fd = -1;
}
}

/**
* 演示视频播放场景中的预读应用
*/
int demo_video_player_scenario() {
const char *filename = "video_sample.dat";
const size_t file_size = 100 * 1024 * 1024; // 100MB
video_player_t player_without, player_with;

printf("=== 视频播放场景中的预读应用 ===\n");

// 创建测试视频文件
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建视频文件失败");
return -1;
}

char *buffer = malloc(1024 * 1024);
if (!buffer) {
perror("分配缓冲区失败");
close(fd);
return -1;
}

// 填充随机视频数据
srand(time(NULL));
for (int i = 0; i < 1024 * 1024; i++) {
buffer&#91;i] = rand() % 256;
}

// 写入文件
size_t written = 0;
while (written < file_size) {
size_t to_write = (file_size - written < 1024 * 1024) ?
file_size - written : 1024 * 1024;
write(fd, buffer, to_write);
written += to_write;
}

free(buffer);
close(fd);
printf("创建了 %.2f MB 的视频测试文件\n", file_size / (1024.0 * 1024.0));

// 测试不使用预读的播放
printf("\n--- 不使用预读的播放测试 ---\n");
memset(&player_without, 0, sizeof(player_without));
player_without.fd = -1;

if (video_player_init(&player_without, filename) == 0) {
video_player_play(&player_without, 0);
video_player_cleanup(&player_without);
}

// 测试使用预读的播放
printf("\n--- 使用预读的播放测试 ---\n");
memset(&player_with, 0, sizeof(player_with));
player_with.fd = -1;

if (video_player_init(&player_with, filename) == 0) {
video_player_play(&player_with, 1);
video_player_cleanup(&player_with);
}

unlink(filename);
return 0;
}

int main() {
return demo_video_player_scenario();
}

示例5:预读策略优化示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>

/**
* 智能预读器
*/
typedef struct {
int fd;
off_t file_size;
off_t last_read_pos;
size_t read_pattern&#91;10]; // 记录最近10次读取的大小
int pattern_index;
int pattern_count;
} smart_readaheater_t;

/**
* 初始化智能预读器
*/
int smart_readaheater_init(smart_readaheater_t *sr, const char *filename) {
sr->fd = open(filename, O_RDONLY);
if (sr->fd == -1) {
perror("打开文件失败");
return -1;
}

struct stat sb;
if (fstat(sr->fd, &sb) == -1) {
perror("获取文件状态失败");
close(sr->fd);
return -1;
}

sr->file_size = sb.st_size;
sr->last_read_pos = 0;
sr->pattern_index = 0;
sr->pattern_count = 0;

memset(sr->read_pattern, 0, sizeof(sr->read_pattern));

printf("智能预读器初始化完成\n");
printf("文件大小: %.2f MB\n", sr->file_size / (1024.0 * 1024.0));

return 0;
}

/**
* 分析读取模式
*/
size_t analyze_read_pattern(smart_readaheater_t *sr) {
if (sr->pattern_count < 3) {
return 1024 * 1024; // 默认1MB
}

// 计算平均读取大小
size_t total = 0;
int count = (sr->pattern_count < 10) ? sr->pattern_count : 10;

for (int i = 0; i < count; i++) {
total += sr->read_pattern&#91;i];
}

return total / count;
}

/**
* 智能预读
*/
int smart_readahead(smart_readaheater_t *sr, off_t pos, size_t size) {
// 记录本次读取模式
sr->read_pattern&#91;sr->pattern_index] = size;
sr->pattern_index = (sr->pattern_index + 1) % 10;
if (sr->pattern_count < 10) {
sr->pattern_count++;
}

// 分析读取模式
size_t predicted_size = analyze_read_pattern(sr);

// 预测下一个读取位置
off_t next_pos = pos + size;

// 如果下一个位置有效,则进行预读
if (next_pos < sr->file_size) {
size_t readahead_size = predicted_size * 2; // 预读两倍大小
if (next_pos + readahead_size > sr->file_size) {
readahead_size = sr->file_size - next_pos;
}

if (readahead(sr->fd, next_pos, readahead_size) == 0) {
printf("智能预读: 位置 %ld, 大小 %zu\n", next_pos, readahead_size);
return 0;
}
}

return -1;
}

/**
* 读取数据并触发智能预读
*/
ssize_t smart_read(smart_readaheater_t *sr, void *buf, size_t count, off_t offset) {
ssize_t bytes_read = pread(sr->fd, buf, count, offset);
if (bytes_read > 0) {
smart_readahead(sr, offset, bytes_read);
sr->last_read_pos = offset + bytes_read;
}
return bytes_read;
}

/**
* 演示智能预读策略
*/
int demo_smart_readahead() {
const char *filename = "smart_test.dat";
const size_t file_size = 50 * 1024 * 1024; // 50MB
smart_readaheater_t sr;

printf("=== 智能预读策略示例 ===\n");

// 创建测试文件
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
return -1;
}

char *buffer = malloc(1024 * 1024);
if (!buffer) {
perror("分配缓冲区失败");
close(fd);
return -1;
}

// 填充测试数据
for (size_t i = 0; i < 1024 * 1024; i++) {
buffer&#91;i] = 'A' + (i % 26);
}

// 写入文件
size_t written = 0;
while (written < file_size) {
size_t to_write = (file_size - written < 1024 * 1024) ?
file_size - written : 1024 * 1024;
write(fd, buffer, to_write);
written += to_write;
}

free(buffer);
close(fd);
printf("创建了 %.2f MB 的测试文件\n", file_size / (1024.0 * 1024.0));

// 初始化智能预读器
if (smart_readaheater_init(&sr, filename) != 0) {
unlink(filename);
return -1;
}

// 模拟不同模式的读取
printf("\n开始智能预读测试:\n");

char *read_buffer = malloc(2 * 1024 * 1024); // 2MB缓冲区
if (!read_buffer) {
perror("分配读取缓冲区失败");
close(sr.fd);
unlink(filename);
return -1;
}

// 模拟顺序读取
printf("1. 顺序读取模式:\n");
for (off_t pos = 0; pos < 20 * 1024 * 1024; pos += 512 * 1024) {
ssize_t bytes_read = smart_read(&sr, read_buffer, 512 * 1024, pos);
if (bytes_read > 0) {
printf(" 读取位置 %ld, 大小 %zd\n", pos, bytes_read);
}
}

// 模拟随机读取
printf("\n2. 随机读取模式:\n");
srand(time(NULL));
for (int i = 0; i < 5; i++) {
off_t pos = (rand() % (int)(file_size - 1024 * 1024));
size_t size = 256 * 1024 + (rand() % (768 * 1024));
ssize_t bytes_read = smart_read(&sr, read_buffer, size, pos);
if (bytes_read > 0) {
printf(" 随机读取位置 %ld, 大小 %zd\n", pos, bytes_read);
}
}

free(read_buffer);
close(sr.fd);
unlink(filename);

printf("\n智能预读策略特点:\n");
printf(" - 学习读取模式\n");
printf(" - 动态调整预读大小\n");
printf(" - 适应不同的访问模式\n");

return 0;
}

int main() {
return demo_smart_readahead();
}

readahead 使用注意事项

适用场景:

大文件顺序访问: 读取大型文件时特别有效

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

可预测的访问模式: 顺序读取或规律性访问

I/O密集型应用: 数据库、媒体播放器、文件传输工具

不适用场景:

随机访问: 频繁随机访问的文件不适合预读

小文件: 文件很小时预读开销大于收益

内存紧张: 系统内存不足时预读可能降低性能

性能考虑:

预读大小: 需要根据具体场景调整预读大小

时机选择: 合适的预读时机很重要

系统负载: 高负载时谨慎使用预读

错误处理:

检查返回值: readahead失败时不会影响正常读取

权限检查: 确保有足够的权限访问文件

文件状态: 文件必须是打开状态且支持预读

总结

readahead 是一个强大的预读工具,能够显著提高顺序访问大文件的性能。通过合理的预读策略,可以减少I/O等待时间,提高应用程序的响应速度。在实际应用中,需要根据具体的访问模式和系统环境来设计合适的预读策略。

readahead系统调用及示例-CSDN博客

https://www.calcguide.tech/2025/08/28/readahead系统调用及示例/

data-ad-format="auto" data-full-width-responsive="true">