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 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
| #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <errno.h> #include <string.h> #include <sys/syscall.h>
// 系统调用包装 static int fadvise64_wrapper(int fd, off_t offset, off_t len, int advice) { return syscall(__NR_fadvise64, fd, offset, len, advice); }
// 创建测试文件 int create_test_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(4096); if (buffer) { memset(buffer, 'A', 4096); for (size_t i = 0; i < size; i += 4096) { size_t write_size = (size - i > 4096) ? 4096 : (size - i); write(fd, buffer, write_size); } free(buffer); } return fd; }
int main() { int fd; int result; printf("=== Fadvise64 函数示例 ===\n"); // 示例1: 基本使用 printf("\n示例1: 基本使用\n"); // 创建大文件用于测试 fd = create_test_file("test_fadvise64.dat", 1024 * 1024); // 1MB if (fd == -1) { exit(EXIT_FAILURE); } printf("创建测试文件: test_fadvise64.dat (1MB)\n"); close(fd); // 重新打开文件进行测试 fd = open("test_fadvise64.dat", O_RDONLY); if (fd == -1) { perror("打开测试文件失败"); unlink("test_fadvise64.dat"); exit(EXIT_FAILURE); } printf("打开测试文件进行fadvise64测试\n"); // 示例2: 不同的访问建议 printf("\n示例2: 不同的访问建议\n"); // POSIX_FADV_NORMAL - 普通访问模式 result = fadvise64_wrapper(fd, 0, 0, POSIX_FADV_NORMAL); if (result == 0) { printf("设置POSIX_FADV_NORMAL成功\n"); } else { printf("设置POSIX_FADV_NORMAL失败: %s\n", strerror(errno)); } // POSIX_FADV_SEQUENTIAL - 顺序访问 result = fadvise64_wrapper(fd, 0, 1024*1024, POSIX_FADV_SEQUENTIAL); if (result == 0) { printf("设置POSIX_FADV_SEQUENTIAL成功\n"); printf("提示内核将进行顺序访问,优化预读策略\n"); } // POSIX_FADV_RANDOM - 随机访问 result = fadvise64_wrapper(fd, 0, 1024*1024, POSIX_FADV_RANDOM); if (result == 0) { printf("设置POSIX_FADV_RANDOM成功\n"); printf("提示内核将进行随机访问,减少预读\n"); } // POSIX_FADV_WILLNEED - 数据即将被访问 result = fadvise64_wrapper(fd, 0, 64*1024, POSIX_FADV_WILLNEED); if (result == 0) { printf("设置POSIX_FADV_WILLNEED成功\n"); printf("提示内核预读前64KB数据\n"); } // POSIX_FADV_DONTNEED - 数据不再需要 result = fadvise64_wrapper(fd, 0, 64*1024, POSIX_FADV_DONTNEED); if (result == 0) { printf("设置POSIX_FADV_DONTNEED成功\n"); printf("提示内核可以丢弃前64KB数据的缓存\n"); } // POSIX_FADV_NOREUSE - 数据只访问一次 result = fadvise64_wrapper(fd, 64*1024, 64*1024, POSIX_FADV_NOREUSE); if (result == 0) { printf("设置POSIX_FADV_NOREUSE成功\n"); printf("提示内核64KB-128KB范围的数据只访问一次\n"); } // 示例3: 错误处理演示 printf("\n示例3: 错误处理演示\n"); // 使用无效的文件描述符 result = fadvise64_wrapper(999, 0, 1024, POSIX_FADV_NORMAL); if (result == -1) { if (errno == EBADF) { printf("无效文件描述符错误处理正确: %s\n", strerror(errno)); } } // 使用无效的建议类型 result = fadvise64_wrapper(fd, 0, 1024, 999); if (result == -1) { if (errno == EINVAL) { printf("无效建议类型错误处理正确: %s\n", strerror(errno)); } } // 使用负的偏移量 result = fadvise64_wrapper(fd, -1024, 1024, POSIX_FADV_NORMAL); if (result == -1) { printf("负偏移量处理: %s\n", strerror(errno)); } // 示例4: 实际使用场景演示 printf("\n示例4: 实际使用场景演示\n"); // 场景1: 大文件顺序读取 printf("场景1: 大文件顺序读取优化\n"); printf("处理大日志文件的代码示例:\n"); printf("int process_large_log(const char* filename) {\n"); printf(" int fd = open(filename, O_RDONLY);\n"); printf(" if (fd == -1) return -1;\n"); printf(" \n"); printf(" // 提示内核将顺序访问整个文件\n"); printf(" posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);\n"); printf(" \n"); printf(" // 读取处理文件...\n"); printf(" char buffer[8192];\n"); printf(" ssize_t bytes;\n"); printf(" while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) {\n"); printf(" // 处理数据\n"); printf(" }\n"); printf(" \n"); printf(" close(fd);\n"); printf(" return 0;\n"); printf("}\n\n"); // 场景2: 随机访问数据库文件 printf("场景2: 随机访问数据库文件\n"); printf("数据库文件访问优化:\n"); printf("int access_database_file(const char* filename) {\n"); printf(" int fd = open(filename, O_RDWR);\n"); printf(" if (fd == -1) return -1;\n"); printf(" \n"); printf(" // 提示内核将随机访问文件\n"); printf(" posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);\n"); printf(" \n"); printf(" // 根据需要预读特定区域\n"); printf(" posix_fadvise(fd, index_offset, index_size, POSIX_FADV_WILLNEED);\n"); printf(" \n"); printf(" // 访问完成后释放不需要的缓存\n"); printf(" posix_fadvise(fd, old_data_offset, old_data_size, POSIX_FADV_DONTNEED);\n"); printf(" \n"); printf(" close(fd);\n"); printf(" return 0;\n"); printf("}\n\n"); // 示例5: 不同建议类型的效果说明 printf("示例5: 不同建议类型的效果说明\n"); printf("POSIX_FADV_NORMAL:\n"); printf(" - 默认访问模式\n"); printf(" - 使用系统默认的预读和缓存策略\n"); printf(" - 适用于一般情况\n\n"); printf("POSIX_FADV_SEQUENTIAL:\n"); printf(" - 优化顺序访问\n"); printf(" - 增加预读量\n"); printf(" - 适用于大文件顺序读取\n"); printf(" - 提高顺序读取性能\n\n"); printf("POSIX_FADV_RANDOM:\n"); printf(" - 优化随机访问\n"); printf(" - 减少或禁用预读\n"); printf(" - 适用于数据库、索引文件\n"); printf(" - 减少不必要的内存占用\n\n"); printf("POSIX_FADV_NOREUSE:\n"); printf(" - 数据只访问一次\n"); printf(" - 访问后尽快释放缓存\n"); printf(" - 适用于一次性处理的大文件\n"); printf(" - 节省内存资源\n\n"); printf("POSIX_FADV_WILLNEED:\n"); printf(" - 数据即将被访问\n"); printf(" - 提前预读数据到缓存\n"); printf(" - 适用于已知访问模式的场景\n"); printf(" - 减少实际访问时的等待\n\n"); printf("POSIX_FADV_DONTNEED:\n"); printf(" - 数据不再需要\n"); printf(" - 尽快释放缓存空间\n"); printf(" - 适用于处理完成的数据\n"); printf(" - 释放系统资源\n\n"); // 示例6: 性能测试演示 printf("示例6: 性能影响演示\n"); printf("fadvise64对性能的影响:\n"); printf("1. 正确使用可显著提高I/O性能\n"); printf("2. 错误使用可能导致性能下降\n"); printf("3. 效果因文件系统和硬件而异\n"); printf("4. 大文件效果更明显\n"); printf("5. 需要根据实际访问模式选择\n\n"); // 示例7: 实际应用建议 printf("示例7: 实际应用建议\n"); printf("使用fadvise64的最佳实践:\n"); printf("1. 在文件打开后尽早设置建议\n"); printf("2. 根据实际访问模式选择合适的建议\n"); printf("3. 对于大文件效果更明显\n"); printf("4. 不要过度使用,避免增加系统负担\n"); printf("5. 在长时间运行的应用中适时调整\n"); printf("6. 测试不同建议对性能的影响\n\n"); printf("常见应用场景:\n"); printf("- 大文件处理和分析\n"); printf("- 数据库系统\n"); printf("- 日志处理系统\n"); printf("- 备份和归档工具\n"); printf("- 媒体播放器\n"); printf("- 科学计算应用\n\n"); // 示例8: 与相关函数的对比 printf("示例8: 与相关函数的对比\n"); printf("fadvise64 vs madvise:\n"); printf("fadvise64:\n"); printf(" - 针对文件I/O\n"); printf(" - 影响文件缓存策略\n"); printf(" - 在文件描述符上操作\n\n"); printf("madvise:\n"); printf(" - 针对内存映射\n"); printf(" - 影响内存管理策略\n"); printf(" - 在内存地址上操作\n\n"); printf("fadvise64 vs readahead:\n"); printf("fadvise64:\n"); printf(" - 更通用的建议机制\n"); printf(" - 支持多种访问模式\n"); printf(" - 可以指定文件区域\n\n"); printf("readahead:\n"); printf(" - 专门用于预读\n"); printf(" - 立即执行预读操作\n"); printf(" - 较为直接但不够灵活\n\n"); // 清理资源 close(fd); unlink("test_fadvise64.dat"); printf("总结:\n"); printf("fadvise64是Linux提供的文件访问优化机制\n"); printf("通过向内核提供访问建议来优化性能\n"); printf("支持多种访问模式的优化\n"); printf("是处理大文件和特定访问模式的重要工具\n"); printf("需要根据实际应用场景合理使用\n"); return 0; }
|