比如我们要将enable由True改为False代表禁用该功能。同时另一个线程读取仲裁服务器的ip以不停探测仲裁服务运行状态。则必须保证文件修改操作具有原子性。即使使用 with 打开,还是会有一个窗口导致文件被打开但是新内容没有被刷写,此时意外掉电或重新进入窗口,则可能会导致:数据修改失效、文件被清空等,即无法避免竞态操作。
解决方案
一种可行的方案是让文件真正落盘,然后对文件重命名。参考代码:
python
import os import tempfile
import os import tempfile from contextlib import contextmanager
@contextmanager deftempfile_cmgr(suffix='', dir=None): """ Context for temporary file. Will find a free temporary filename upon entering and will try to delete the file on leaving, even in case of an exception. Parameters ---------- suffix : string optional file suffix dir : string optional directory to save temporary file in """
@contextmanager defopen_atomic(filepath, *args, **kwargs): """ Open temporary file object that atomically moves to destination upon exiting. Allows reading and writing to and from the same filename. The file will not be moved to destination in case of an exception. Parameters ---------- filepath : string the file path to be opened fsync : bool whether to force write the file to disk *args : mixed Any valid arguments for :code:`open` **kwargs : mixed Any valid keyword arguments for :code:`open` """ fsync = kwargs.get('fsync', False)
with tempfile_cmgr(dir=os.path.dirname(os.path.abspath(filepath))) as tmppath: withopen(tmppath, *args, **kwargs) as file: try: yield file finally: # make sure that all data is on disk 确保数据刷写到银盘上 # see http://stackoverflow.com/questions/7433057/is-rename-without-fsync-safe if fsync: file.flush() os.fsync(file.fileno()) os.rename(tmppath, filepath)