别再让脚本“撞车”——用 WaitLock 给 Shell 加个红绿灯
“
当多个脚本同时读写一份数据库、同一块磁盘,甚至同一台 GPU 时,结果常常是一场灾难:备份文件被覆盖、下载任务互相抢占、日志里塞满“device busy”。
WaitLock 这个小工具就像十字路口的红绿灯,帮你在 Shell 层面实现 互斥锁 和 信号量,让多进程井然有序。本文带你从零安装到高阶实战,一次看懂它的全部玩法。
为什么会有 WaitLock?
日常写脚本时,我们常用 flock
、lockfile
等命令给文件加锁,但它们要么语法冗长,要么在进程异常退出时留下“僵尸锁”。
WaitLock 的设计初衷就是解决这些痛点:
- •
语法简洁:一条命令就能加锁、执行脚本、自动释放。 - •
自动清理:进程崩溃、被杀、正常退出都会解锁,不怕“僵尸”。 - •
跨平台:纯 C 写成,Linux、macOS、*BSD 都能跑。 - •
两种模式: - •
互斥锁(mutex):同一时刻只允许一个进程干活。 - •
信号量(semaphore):允许 N 个进程并行,适合做线程池、GPU 池。
- •
安装:三步搞定
1. 准备编译环境
Ubuntu / Debian
sudo apt-get update
sudo apt-get install build-essential autoconf
CentOS / Rocky
sudo yum groupinstall "Development Tools"
sudo yum install autoconf
macOS
# 先装 Xcode Command Line Tools
xcode-select --install
# 推荐用 Homebrew 装 autoconf
brew install autoconf
2. 下载并编译
git clone https://github.com/user/waitlock.git
cd waitlock
# 如果你拿到的是源码压缩包,直接解压即可
autoreconf -fi # 只在 Git 仓库里需要
./configure
make
3. 安装到系统
sudo make install
# 默认装到 /usr/local/bin/waitlock
# 想换路径:
# ./configure --prefix=/opt/waitlock
# make install
装完后,敲 waitlock --version
能看到 1.0.0
即成功。
一分钟上手
场景 1:每天凌晨只跑一次备份
#!/bin/bash
# backup.sh
# 如果已有备份在跑,直接退出
waitlock nightly_backup || { echo "备份已在进行中"; exit 1; }
mysqldump --all-databases > all.sql
tar czf all.sql.tgz all.sql
执行:
chmod +x backup.sh
./backup.sh &
./backup.sh # 第二次会提示“备份已在进行中”
场景 2:允许 4 个并行下载
#!/bin/bash
# download.sh
waitlock --allowMultiple 4 download_slot || { echo "下载队列已满"; exit 1; }
wget "$1"
配合 xargs 实现批量并行下载:
cat url.list | xargs -n1 -P8 ./download.sh
当活跃进程达到 4 个时,其余脚本自动排队。
命令速查表:用哪条参数做什么
高阶玩法:把 WaitLock 用到极致
1. 基于环境变量的全局配置
在 /etc/profile.d/waitlock.sh
放一行:
export WAITLOCK_TIMEOUT=300
export WAITLOCK_DIR="/var/lock/myapp"
此后任何脚本都不用写 -t 300
,默认 5 分钟超时,统一管理。
2. 在 CI/CD 里防止并发部署
GitLab CI 例子:
deploy:
stage: deploy
script:
- waitlock deploy_lock --timeout 600 --exec ./deploy.sh
当多人同时 push 时,只有第一个 pipeline 真正执行部署,其余排队或超时失败,避免生产环境冲突。
3. GPU 资源池
实验室有 8 张显卡,希望每人最多用 2 张,且系统留 1 张:
waitlock -c -x 1 gpu_pool
export CUDA_VISIBLE_DEVICES=$WAITLOCK_SLOT
python train.py
$WAITLOCK_SLOT
会自动变成 0–6 之间的一个数字,脚本零改动。
4. NFS 共享目录锁
多台节点共用 NFS:
export WAITLOCK_DIR="/mnt/nfs/locks"
waitlock cluster_job --timeout 300 --exec ./mpi_job.sh
WaitLock 的文件锁在 NFS 上同样有效,实现跨主机互斥。
5. 批量处理文件并控制并发
把 1000 个 CSV 交给 3 个进程并行处理:
find /data -name "*.csv" | \
xargs -P10 -I{} waitlock -m3 processor --exec "python process.py {}"
xargs -P10
一次起 10 个进程,WaitLock 再把并发度降到 3。
常见疑问与排查
性能小贴士
-
锁目录放 tmpfs
如果机器内存充裕,把/var/lock/waitlock
挂到 tmpfs,减少磁盘 IO。sudo mount -t tmpfs -o size=10M tmpfs /var/lock/waitlock
-
层级命名避免单目录文件过多
用project/subsystem/task
这样的描述符,减少单次扫描文件数。 -
合理设置超时
太短容易误杀,太长会拖慢队列。根据任务平均耗时调整。
写在最后
WaitLock 把“锁”这件事做到了极简:
- •
一条命令,解决并发冲突。 - •
进程退出,自动打扫战场。 - •
支持互斥、信号量、CPU 感知、NFS 共享,几乎涵盖日常脚本的所有场景。
下次写备份、跑训练、发版时,不妨把 waitlock
当成习惯动作——就像进地铁先刷卡一样自然。
祝你的脚本从此不再“撞车”。
参考链接
- •
项目主页与源码:https://github.com/user/waitlock - •
安装后阅读: man waitlock