C中的多线程读取和打印非常大的文件
Multithreading in C to read and print a very large file
我有一个非常大的文件要读取并执行以下操作。
- 打开大文件 (>50MB) 并逐行阅读
- 执行一些比较操作
- 打印比较结果
- Return
当我在单线程 C 代码中执行上述序列时,它工作正常,现在我试图通过创建 3 个线程来使用多线程来使其更快(我被授权使用 3 个线程来使这个过程更快) 阅读和比较,但我没有这样做,因为我看到它只是重复了一些比较。
有什么方法可以让我使用 3 个线程读取文件的 3 个不同部分并执行一些操作吗?
请注意,这个答案是一个“技巧”(或者可能是分配是一个技巧?),因为它并没有真正使过程更快。答案假定标准 Linux 计算机具有合理的 (4G+) 内存。
简短回答:在任何半正经的配置中,数据将移动到 OS 缓冲区,问题实际上是 CPU 绑定,而不是 IO 绑定。
长答案:
虽然 50MB 的文件对于人类来说是 'Large',但对于每台现代计算机来说都是 'Small'。实际上,数据将移入 OS 缓冲区,并会留在那里,除非系统需要内存用于其他任务。
给定数据在 (OS) 内存中,问题(初始调用除外)不是 IO 绑定的,而是 CPU 绑定的。对于这个 3 线程 MT 程序将发挥神奇作用。问题变成了如何将工作分散到 3 个文件中。理想情况下,3 个线程会将文件分成 3 个(几乎)相等的块,每个块单独处理。
解决方案是伪代码,实际代码必须处理分割块的行的处理、错误检查等。
FILE *data_fp ;
static int block_size ;
main() {
data_fp = fopen(...) ;
int filesize = ftell(fp) ;
block_size = filesize/6 ;
for (int i=0 ; i<N_THREADS ; i++ ) {
start_offset = filefize*((float i)/N_THREADS) ;
pthread_create(search_start, ... , &start_offset) ;
}
}
search_start(void *arg) {
// Extract the offset to start
long start_offset = * (long *) arg ;
// Create separate FILE*, with separate position, buffers, etc.
FILE *local_fp = fdopen(fileno(data_fp), "r") ;
// Position at the thread specific offset
fseek(local_fp, start_offset, SEEK_SET) ;
char buff[256] ; // max line size
// Loop until EOF, some exit condition, or block_size characters processed
for (long p = 0 ; p < block_size && fgets(buff, sizeof(buff), local_fp) ; p += strlen(buff)) {
// Compare, check, whatever is needed
...
if (need_to_stop) break ;
} ;
fclose(local_fp) ;
}
使用 'mmap' 可能会更快。但是,问题要求行处理,鉴于这不是现实生活中的问题,不确定是否值得付出额外的努力。
我有一个非常大的文件要读取并执行以下操作。
- 打开大文件 (>50MB) 并逐行阅读
- 执行一些比较操作
- 打印比较结果
- Return
当我在单线程 C 代码中执行上述序列时,它工作正常,现在我试图通过创建 3 个线程来使用多线程来使其更快(我被授权使用 3 个线程来使这个过程更快) 阅读和比较,但我没有这样做,因为我看到它只是重复了一些比较。
有什么方法可以让我使用 3 个线程读取文件的 3 个不同部分并执行一些操作吗?
请注意,这个答案是一个“技巧”(或者可能是分配是一个技巧?),因为它并没有真正使过程更快。答案假定标准 Linux 计算机具有合理的 (4G+) 内存。
简短回答:在任何半正经的配置中,数据将移动到 OS 缓冲区,问题实际上是 CPU 绑定,而不是 IO 绑定。
长答案:
虽然 50MB 的文件对于人类来说是 'Large',但对于每台现代计算机来说都是 'Small'。实际上,数据将移入 OS 缓冲区,并会留在那里,除非系统需要内存用于其他任务。
给定数据在 (OS) 内存中,问题(初始调用除外)不是 IO 绑定的,而是 CPU 绑定的。对于这个 3 线程 MT 程序将发挥神奇作用。问题变成了如何将工作分散到 3 个文件中。理想情况下,3 个线程会将文件分成 3 个(几乎)相等的块,每个块单独处理。
解决方案是伪代码,实际代码必须处理分割块的行的处理、错误检查等。
FILE *data_fp ;
static int block_size ;
main() {
data_fp = fopen(...) ;
int filesize = ftell(fp) ;
block_size = filesize/6 ;
for (int i=0 ; i<N_THREADS ; i++ ) {
start_offset = filefize*((float i)/N_THREADS) ;
pthread_create(search_start, ... , &start_offset) ;
}
}
search_start(void *arg) {
// Extract the offset to start
long start_offset = * (long *) arg ;
// Create separate FILE*, with separate position, buffers, etc.
FILE *local_fp = fdopen(fileno(data_fp), "r") ;
// Position at the thread specific offset
fseek(local_fp, start_offset, SEEK_SET) ;
char buff[256] ; // max line size
// Loop until EOF, some exit condition, or block_size characters processed
for (long p = 0 ; p < block_size && fgets(buff, sizeof(buff), local_fp) ; p += strlen(buff)) {
// Compare, check, whatever is needed
...
if (need_to_stop) break ;
} ;
fclose(local_fp) ;
}
使用 'mmap' 可能会更快。但是,问题要求行处理,鉴于这不是现实生活中的问题,不确定是否值得付出额外的努力。