我有两个协作程序 X 和 Y 在同一系统上运行。 X有时使用Y来计算一些信息。我在程序之间使用基于文件的通信。当 X 希望 Y 计算某些内容时,过程如下:
- X 将工作描述写入文件 job.txt 并将其放入共享目录中。然后X开始轮询同一目录中是否存在ready.txt文件。
- Y 轮询文件 job.txt 是否存在。当文件出现时,Y首先从文件中读取作业信息并将其删除。然后Y执行作业并将结果放入result.txt中。最后Y创建了一个ready.txt文件并再次开始轮询job.txt是否存在。
- 当X注意到ready.txt的出现时,它会读取result.txt,删除ready.txt和result.txt,然后继续做其他事情。
问题是 X 有时只收到空的或部分结果文件。 Y 使用 bash 脚本,当前执行如下操作:
rm -f tmp_result.txt
for ((i=first; i <= last; i++)) # Each iteration produces 1 or more result lines
do
# Compute something...
echo "One result line with e.g. $values" >> tmp_result.txt
done
cp tmp_result.txt result.txt
touch ready.txt
也就是说,使用 echo 和 I/O 重定向将结果文件的内容一次一行打印到临时文件中。当内容准备好(或应该准备好!)时,它们将被复制到最终的 result.txt 文件中,并通过创建 read.txt 来通知 X。
即使经过相当广泛的实验和谷歌搜索后,我仍然无法找到一种方法来确保 X 始终收到完整的结果。也许 100 次中有 1 到 5 次,X 会将 result.txt 视为完全空(最常见的情况)或仅包含部分结果。
关于脚本逻辑的一些澄清:我最初将结果行直接回显到 result.txt,但这非常不可靠(可能 2 个结果中有 1 个是不完整的)。然后我改为首先将这些行回显到 tmp_result.txt,然后将 tmp_result.txt 移动(重命名)到 result.txt。这导致大约十分之一的结果不完整。如上所示,复制文件效果最佳,但偶尔也会失败。
那么,在 X 开始读取文件之前,如何确保所有回显行都已正确复制到 result.txt 中? Y 只有一些核心 bash 工具可用。
编辑:23 条补充意见
- 我已经验证(例如,通过不删除 tmp_result.txt 然后检查它)问题不在于原始结果,而在于它们如何传输到 X。
- tmp_result.txt 和 result.txt 都驻留在基于 tmpfs 的 RAM 磁盘上,因此我希望复制/移动文件的速度非常快。
- 我在开始使用 tmpfs 后第一次遇到这个问题(最初所有文件都驻留在普通硬盘分区中)。
答案1
看来您可以使用 FIFO 来实现此目的:
mkfifo tasks
制作人:
for i in {1..10}; do echo "task$i"; done > tasks
消费者:
while read task; do echo "received $task"; done <tasks
这样,您就不必关心同步或删除,也不会在轮询上浪费任何 CPU 时间——如果没有数据或者生产者还没有打开 FIFO,消费者就会阻塞(从而节省 CPU 时间)。如果 FIFO 已满或者消费者还没有打开 FIFO,那么生产者就会阻塞。
答案2
尝试将命令放在 和sync
之间。cp
touch ready.txt