研究想法如何落地:用AI辅助生成研究草案并一键验证
2026/9/29 21:56:24
编辑命令:
gcc -O2 -pthread -std=c11 -o fastdu fastdu.c
运行命令:
./fastdu # 用当前系统 CPU 核数个线程
./fastdu -j 16 # 手动指定 16 线程
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include <sys/stat.h> #include <unistd.h> #include <pthread.h> typedef struct { char *path; int root; } task_t; static struct { task_t *buf; int cap, head, count; int active; /* 已弹出但未完成的任务数 */ pthread_mutex_t mtx; pthread_cond_t cond; } Q; static long long *root_sizes; static void queue_init(int cap) { Q.cap = cap > 0 ? cap : 64; Q.buf = malloc(sizeof(task_t) * Q.cap); Q.head = Q.count = Q.active = 0; pthread_mutex_init(&Q.mtx, NULL); pthread_cond_init(&Q.cond, NULL); } /* 取任务;返回 0 表示全部完成 */ static int queue_pop(task_t *out) { pthread_mutex_lock(&Q.mtx); while (Q.head == Q.count && Q.active > 0) pthread_cond_wait(&Q.cond, &Q.mtx); if (Q.head == Q.count) { pthread_mutex_unlock(&Q.mtx); return 0; } *out = Q.buf[Q.head++]; if (Q.head == Q.count) Q.head = Q.count = 0; /* 顺带回收数组头部 */ Q.active++; pthread_mutex_unlock(&Q.mtx); return 1; } static void queue_push(char *path, int root) { /* 接管 path 所有权 */ pthread_mutex_lock(&Q.mtx); if (Q.count == Q.cap) { if (Q.head > 0) { /* 先压缩再扩容 */ int n = Q.count - Q.head; memmove(Q.buf, Q.buf + Q.head, sizeof(task_t) * n); Q.head = 0; Q.count = n; } if (Q.count == Q.cap) { Q.cap *= 2; Q.buf = realloc(Q.buf, sizeof(task_t) * Q.cap); } } Q.buf[Q.count].path = path; Q.buf[Q.count].root = root; Q.count++; pthread_cond_signal(&Q.cond); pthread_mutex_unlock(&Q.mtx); } static void queue_done(void) { pthread_mutex_lock(&Q.mtx); Q.active--; if (Q.active == 0 && Q.head == Q.count) pthread_cond_broadcast(&Q.cond); pthread_mutex_unlock(&Q.mtx); } static inline void add_size(int root, long long sz) { __atomic_fetch_add(&root_sizes[root], sz, __ATOMIC_RELAXED); } static void *worker(void *arg) { (void)arg; task_t t; while (queue_pop(&t)) { DIR *d = opendir(t.path); if (d) { size_t plen = strlen(t.path); struct dirent *e; while ((e = readdir(d)) != NULL) { const char *n = e->d_name; if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) continue; /* 跳过 . 和 .. */ size_t nlen = strlen(n); char *full = malloc(plen + nlen + 2); memcpy(full, t.path, plen); full[plen] = '/'; memcpy(full + plen + 1, n, nlen + 1); if (e->d_type == DT_DIR) { queue_push(full, t.root); } else if (e->d_type == DT_REG) { struct stat st; if (stat(full, &st) == 0) add_size(t.root, st.st_size); free(full); } else if (e->d_type == DT_UNKNOWN) { struct stat st; /* 某些文件系统 d_type 无效 */ if (lstat(full, &st) == 0) { if (S_ISDIR(st.st_mode)) queue_push(full, t.root); else { add_size(t.root, st.st_size); free(full); } } else free(full); } else { free(full); /* 符号链接/fifo 等直接忽略 */ } } closedir(d); } free(t.path); queue_done(); } return NULL; } static void fmt_size(long long sz, char *buf, size_t buflen) { static const char *u[] = {"", "K", "M", "G", "T", "P"}; double v = (double)sz; int i = 0; while (v >= 1024.0 && i < 5) { v /= 1024.0; i++; } if (i == 0) snprintf(buf, buflen, "%lld", sz); else if (v < 10.0) snprintf(buf, buflen, "%.1f%s", v, u[i]); else snprintf(buf, buflen, "%.0f%s", v, u[i]); } static int cmp_str(const void *a, const void *b) { return strcmp(*(char * const *)a, *(char * const *)b); } int main(int argc, char **argv) { int nthreads = 0, opt; while ((opt = getopt(argc, argv, "j:")) != -1) if (opt == 'j') nthreads = atoi(optarg); if (nthreads <= 0) { long n = sysconf(_SC_NPROCESSORS_ONLN); nthreads = (n > 0) ? (int)n : 4; } if (nthreads > 64) nthreads = 64; DIR *d = opendir("."); if (!d) { perror("opendir"); return 1; } char **names = NULL; int nn = 0, cap = 0; struct dirent *e; while ((e = readdir(d)) != NULL) { if (e->d_name[0] == '.') continue; /* 与 ./* 通配一致 */ if (cap == nn) { cap = cap ? cap * 2 : 64; names = realloc(names, sizeof(char *) * cap); } names[nn++] = strdup(e->d_name); } closedir(d); qsort(names, nn, sizeof(char *), cmp_str); root_sizes = calloc(nn > 0 ? nn : 1, sizeof(long long)); queue_init(nn > 0 ? nn : 64); for (int i = 0; i < nn; i++) { size_t l = strlen(names[i]) + 3; char *p = malloc(l); snprintf(p, l, "./%s", names[i]); struct stat st; if (lstat(p, &st) == 0) { if (S_ISDIR(st.st_mode)) { queue_push(p, i); continue; } add_size(i, st.st_size); /* 顶层普通文件 */ } free(p); } pthread_t *th = malloc(sizeof(pthread_t) * nthreads); for (int i = 0; i < nthreads; i++) pthread_create(&th[i], NULL, worker, NULL); for (int i = 0; i < nthreads; i++) pthread_join(th[i], NULL); long long total = 0; char buf[32]; for (int i = 0; i < nn; i++) { fmt_size(root_sizes[i], buf, sizeof buf); printf("%8s ./%s\n", buf, names[i]); total += root_sizes[i]; } fmt_size(total, buf, sizeof buf); printf("%8s total\n", buf); return 0; }