如何让python mmap赋值原子?这里没有关于原子的说法:https://docs.python.org/3.0/library/mmap.html
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
我立即在另一个进程中执行以下代码
f = open('mmp', 'r')
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
mm = m[:]
l = struct.unpack("100000000I", mm)
set(l)
然后我看到{888,9999}
这意味着mmap不是原子的。无论如何要使它成为原子?
答案 0 :(得分:3)
一般来说,你不能。无论是通过mmap还是写入,文件写入都不是原子的。一些文件系统,例如Tahoe-LAFS,确实有文件放置操作,但即便如此,它也是已知完成的问题,而不是原子操作(块是单独存储的)。文件内容更新的原子性经常使用三种方法完成:
使用rename调用,您可以确定名称指向旧文件或新文件(Python Path.replace可能更清晰)。这是用于例如maildir
使用file locks。这些通常是合作的,这意味着访问该文件的所有程序必须始终使用相同的锁定方法。有时这是不可能的,例如在某些网络文件系统中。由于这种不一致性,还使用了其他锁定方法,例如lock files - 因此"相同的方法"需求。
使用由于底层架构(例如磁盘扇区)而具有原子性的较小访问。这例如是完成的。在SQLite's journal headers。值得注意的是,阈值与mmap不同,因为内存页面本身可能是共享的,允许更精细的粒度用于原子访问(可能是CPU字大小或单字节)。
主题相当复杂。将任何这些同步方法与mmap组合的关键是mmap.flush。
答案 1 :(得分:1)
我不认为这是mmap
问题 - 我敢打赌它发生了,因为f.close()
只是保证Python已将数据发送到底层操作系统&# 39; s缓冲但但并不意味着它已被实际写入。然后当你再次打开它并将句柄交给mmap
时,你仍然在缓冲区上操作。
您可以在关闭文件之前尝试同步缓冲区,以确保所有内容都已写入:
import os
f = open('mmp', 'wb')
f.write(b1)
f.flush()
os.fsync(f.fileno())
f.close()
或者更好的是,只是为了让Python在出现错误时能够干净地处理关闭:
with open('mmp', 'wb') as f:
f.write(b1)
f.flush()
os.fsync(f.fileno())
虽然即使os.fsync()
不是100%保证,但是来自基础fsync()
手册页:
调用fsync()不一定能确保包含该文件的目录中的条目也已到达磁盘。为此,还需要在目录的文件描述符上显式的fsync()。
但我敢打赌,在非常罕见的边缘情况下,它不会做你需要的。