Linux Shell中多进程原子写入队列的可行性探究
如何在Linux Shell中实现多进程原子写入队列?
可以实现,但你当前用命名管道(FIFO)的写法无法保证大内容的一致性——Linux管道的写入只有当数据量小于PIPE_BUF(通常为4096字节)时才是原子的,超过这个大小的内容会被拆分传输,导致多个进程的输出混在一起。
下面提供两种可靠的实现方案:
方案一:临时文件+原子移动(推荐)
利用Linux下mv命令的原子性(同文件系统内重命名操作不会被中断),每个进程先将内容写入临时文件,再原子性地将文件移入队列目录,完全避免内容混合。
#!/bin/bash # 创建临时目录存储队列任务 queue_dir=$(mktemp -d) # 封装原子写入函数 atomic_write() { local target_url=$1 # 生成唯一临时文件 local temp_file=$(mktemp -p "$queue_dir") # 写入内容到临时文件 curl "$target_url" > "$temp_file" # 原子重命名为队列任务文件(时间戳保证唯一性) mv "$temp_file" "$queue_dir/$(date +%s%N).task" } # 启动多进程任务 atomic_write http://www.url1.com & atomic_write http://www.url2.com & # 等待所有后台任务完成 wait # 读取队列内容(顺序可按文件名排序,也可直接遍历) for task_file in "$queue_dir"/*.task; do cat "$task_file" rm "$task_file" done # 清理临时目录 rmdir "$queue_dir"
这种方式不管内容多大,都能保证每个进程的输出完整独立,顺序可以是任意的(也可通过文件名排序控制顺序)。
方案二:管道+自定义分隔符(内容可控场景适用)
如果一定要用管道,可以给每个进程的输出末尾添加唯一分隔符,读取时按分隔符拆分内容。但要确保分隔符不会出现在目标内容中,否则会导致拆分错误。
#!/bin/bash rm -f ./queue mkfifo ./queue # 写入时添加自定义结束标记 curl http://www.url1.com && echo "===TASK_FINISHED===" > ./queue & curl http://www.url2.com && echo "===TASK_FINISHED===" > ./queue & # 按分隔符读取完整内容 awk 'BEGIN{RS="===TASK_FINISHED==="} {print $0}' ./queue rm ./queue
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

