基于Is file append atomic in UNIX?和其他来源,看起来在现代Linux上,我可以在追加模式下打开一个文件并从多个进程写入小块(< PIPE_BUF
)而不用担心撕裂。
使用syswrite
将这些限制扩展到Ruby吗?特别为此代码:
f = File.new('...', 'a')
f.syswrite("short string\n")
我可以期望写入不与其他进程以相同的方式进行交错吗?或者是否有一些我不知道的缓冲/潜在分裂?
假设ruby> = 2.3
答案 0 :(得分:1)
我不会这么认为。 syswrite
调用write
POSIX函数,该函数在处理文件时不会声明原子性。
请参阅:Are POSIX' read() and write() system calls atomic?
Understanding concurrent file writes from multiple processes
Tl; dr-你应该在你的应用程序中实现一些并发控制来同步这种访问。
答案 1 :(得分:1)
我最近研究了这个主题,以便在File appender中实现Rackstash。
你可以在specs中找到我最初从blog post改编的关于此主题的测试,遗憾的是,由于作者没有直接写入文件但其代码很遗憾通过管道。请阅读那里的评论。
使用(1)现代操作系统和(2)通常的本地文件系统,操作系统保证来自多个进程的并发附加写入交错数据。
这里的要点是:
请注意,此机制不保证并发读取器始终读取完整写入。虽然写入本身从不交错,但读者可能会读取正在进行的写入的部分结果。
就我的理解(和我的测试)而言,原子可写的大小甚至不限于PIPE_SIZE
。此限制仅适用于写入类似插槽的管道或例如STDOUT而不是真实的文件。
不幸的是,关于这个主题的权威信息相当稀少。关于此主题的大多数文章(以及SO答案)将严格附加与随机写入混为一谈。如果没有严格追加(通过仅以附加模式打开文件),则保证无效。
因此,回答您的具体问题:是的,在现代操作系统上写入本地文件系统时,您的问题代码应该是安全的。我认为 syswrite
已绕过文件缓冲区。当然,您还应该在写入之前设置f.sync = true
以完全禁用任何缓冲。
请注意,如果您计划从进程中的多个线程写入单个打开的文件,则仍应使用Mutex(或类似)(因为OS的附加保证仅对并发写入不同文件有效 - 描述符;它无法识别同一进程对同一文件描述符的重叠写入。)