如何使python mmap赋值原子化?

2024-05-12 12:35:57 发布

您现在位置:Python中文网/ 问答频道 /正文

如何使python mmap赋值原子化?{这里什么都没说}

huge_list1 = [888 for _ in range(100000000)]
huge_list2 = [9999 for _ in huge_list1]
b1 = struct.pack("100000000I", *huge_list1)
b2 = struct.pack("100000000I", *huge_list1)

f = open('mmp', 'wb')
f.write(b1)
f.close()
f = open('mmp', 'r+')
m = mmap.mmap(f.fileno(), 0)
m[:]=b2

我立即在另一个进程中执行以下代码

^{pr2}$

然后我看到{8889999}

这意味着mmap不是原子的。不管怎样让它原子化?


Tags: inforrangeopenb2structpackb1
2条回答

一般来说,你不能。文件写入不是原子的,不管是通过mmap还是write。有些文件系统,如tahoelafs,确实有一个文件放入操作,但即使在那里,它也是已知完成的问题,而不是原子操作(块是单独存储的)。文件内容更新的原子性通常有三种方法:

  1. 使用rename调用,可以确保名称指向旧文件或新文件(Python的Path.replace可能更清楚)。这是在maildir中使用的方法。

  2. 使用file locks。这些都是一般协作的,这意味着访问文件的所有程序必须一致地使用相同的锁定方法。有时这是不可能的,例如在一些网络文件系统中。由于这种不一致性,还使用了其他锁方法,如lock files,因此需要“相同的方法”。

  3. 使用由于底层架构(如磁盘扇区)而具有原子性的较小访问。这是在SQLite's journal headers中完成的。值得注意的是,这个阈值与mmap不同,因为内存页本身可能是共享的,允许原子访问的粒度更细(可能是CPU字大小或单字节)。

这个话题相当复杂。将这些同步方法与mmap结合的关键是mmap.flush。在

我不认为这是一个mmap问题,我敢打赌这是因为f.close()保证Python已经将数据发送到底层操作系统的缓冲区,但这并不意味着它已经被实际写入。然后当您再次打开它,并将句柄交给mmap,您仍然在对缓冲区进行操作。在

您可以在关闭文件之前尝试同步缓冲区,以确保所有内容都已写入:

import os

f = open('mmp', 'wb')
f.write(b1)
f.flush()
os.fsync(f.fileno()) 
f.close()

或者更好,只是为了让Python在发生错误时干净地处理关闭:

^{pr2}$

尽管os.fsync()不是100%的保证,但从底层的fsync()手册页:

Calling fsync() does not necessarily ensure that the entry in the directory containing the file has also reached disk. For that an explicit fsync() on a file descriptor for the directory is also needed.

但我敢打赌,在非常罕见的边缘情况下,它不能满足你的需要。在

相关问题 更多 >