我能保证Ruby中的原子追加吗?

时间:2018-03-07 00:59:10

标签: ruby linux

基于Is file append atomic in UNIX?和其他来源,看起来在现代Linux上,我可以在追加模式下打开一个文件并从多个进程写入小块(< PIPE_BUF)而不用担心撕裂。

使用syswrite将这些限制扩展到Ruby吗?特别为此代码:

f = File.new('...', 'a')
f.syswrite("short string\n")

我可以期望写入不与其他进程以相同的方式进行交错吗?或者是否有一些我不知道的缓冲/潜在分裂?

假设ruby> = 2.3

2 个答案:

答案 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)通常的本地文件系统,操作系统保证来自多个进程的并发附加写入交错数据。

这里的要点是:

  • 您需要一个相当现代的操作系统。非常古老(或异国情调)的系统具有较少的保证。在这里,您可能必须使用例如明确锁定文件。 File#flock
  • 您需要使用兼容的文件系统。大多数本地文件系统,如HFS,APFS,NTFS,以及通常的Linux文件系统,如ext3,ext4,btrfs,......都应该是安全的。 SMB是为数不多的网络文件系统之一。在这方面,NFS和大多数FUSE文件系统都不安全。

请注意,此机制不保证并发读取器始终读取完整写入。虽然写入本身从不交错,但读者可能会读取正在进行的写入的部分结果。

就我的理解(和我的测试)而言,原子可写的大小甚至不限于PIPE_SIZE。此限制仅适用于写入类似插槽的管道或例如STDOUT而不是真实的文件。

不幸的是,关于这个主题的权威信息相当稀少。关于此主题的大多数文章(以及SO答案)将严格附加与随机写入混为一谈。如果没有严格追加(通过仅以附加模式打开文件),则保证无效。

因此,回答您的具体问题:是的,在现代操作系统上写入本地文件系统时,您的问题代码应该是安全的。我认为 syswrite已绕过文件缓冲区。当然,您还应该在写入之前设置f.sync = true以完全禁用任何缓冲。

请注意,如果您计划从进程中的多个线程写入单个打开的文件,则仍应使用Mutex(或类似)(因为OS的附加保证仅对并发写入不同文件有效 - 描述符;它无法识别同一进程对同一文件描述符的重叠写入。)