写文件操作探微
来源:互联网 发布:压缩比最高的软件 编辑:程序博客网 时间:2024/06/08 13:16
多进程读写同一个文件的问题
不考虑文件内容的错乱,多进程是可以同时读写一个文件的。当一个进程在写,读的进程能否读到最新的内容,取决于最新的内容是否真正写到了磁盘上。
写缓存与写磁盘
磁盘缓存是物理内存的一部分,专门供操作系统用作读写磁盘的缓冲之用。磁盘缓存与“硬盘自带的缓存”是不一样的概念,它的大小是可以动态设置的,而不像硬盘缓存在出厂的时候固定就是32M或64M。
我们通常用到的写文件API,其实是写到磁盘缓存上,可用python语言做一个实验:
if opt == '-w': with open('1.txt', 'w') as writer: writer.write('hehe\n') time.sleep(10)elif opt == '-r': with open('1.txt') as fp: for line in fp: line = line.rstrip() print line
我们在用-w选项写hehe之后不会立刻关闭文件,而是sleep了10s,方便使用-r选项去读文件,读的时候我们发现,除非文件关闭,否则读不出任何内容。这印证了前面的说法,hehe字符串在文件关闭前只在磁盘缓存里,还未真正写到磁盘上,所以读进程无法读出。
如何确保写到磁盘上而不只是磁盘缓存里呢?python文档给出了建议:
file.flush() Flush the internal buffer.Noteflush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior.
文档建议我们flush+fsync,确保内容确实更新到了磁盘。
fsync的帮助也指出了这一点:
os.fsync(fd) Force write of file with filedescriptor fd to disk. On Unix, this calls the native fsync() function; on Windows, the MS _commit() function.If you’re starting with a Python file object f, first do f.flush(), and then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
所谓的“内部缓存”就是磁盘缓存,强制更新到磁盘,linux下用的是大家熟知的fsync,windows下则是_commit函数。
我们将写的代码改成:
if opt == '-w': with open('1.txt', 'w') as writer: writer.write('hehe\n') writer.flush() os.fsync(writer.fileno()) time.sleep(10)
果然,读进程就能在文件尚未关闭时读到hehe字符串了。
但是,fsync是要慎用的,因为每条内容都强制刷新到磁盘,虽然非常可靠,却会带来性能的急剧下降,我们可以在上述例子的基础上改成写10万条字符串,对比“普通写”与“fsync写”的效率,会发现后者的耗时是前者的数千倍甚至是上万倍!这也正是redis的AOF日志虽然提供了fsync级别的磁盘同步却不建议我们使用的原因(也因此redis的日志做不到绝对的单点可靠)。
这里还有一个疑问,按python的文档,flush并不一定能将最新的内容更新到磁盘上,我们查看java file API的文档,发现也有类似的说法。这是为何?我个人的猜测,这里可能存在一个flush门限的问题,即磁盘缓存里的数据未达到一定的比例,操作系统不会将其写入磁盘驱动器,flush这个API只是建议操作系统可以去清空磁盘缓存,而非fsync那样的强制动作。
进程内缓存与磁盘缓存
进程内缓存指的是我在写磁盘缓存前,在自己的程序里再做一个缓存,将多条消息累积到一定的大小,再一次提交给磁盘缓存,这样能提升写的效率。java里一般要在FileWriter之上再套一层BufferedWriter写入,就是这个用途,实测下来,也能有一倍的效率提升。
python语言里没有BufferedWriter,对于10万条字符串的写可以考虑别的方法,比如我们可以每500条拼成一个大的字符串再做写入,实测也有一倍的效率提升。
不过,如同前面的“普通写”与“fsync写”一样,效率的提升不是全无代价,它往往伴随着可靠性的降低。进程内缓存是属于某个进程的,一旦该进程突然core掉,进程内缓存就会丢失,从用户层面看来,就是我明明已经write好了的数据,很可能并未写到磁盘里。相比之下,磁盘缓存就更可靠一些,因为它是由操作系统管理的,与进程无关,除非是机器断电,否则它不会丢失数据,也就是说,即使我的进程core掉,之前write的内容依然可以安全到达磁盘上。当然,如果追求极致的可靠而不恤性能,fsync是最好的选择。
- 写文件操作探微
- 文件操作 写文件
- 文件写操作
- yaffs2写文件操作
- php写文件操作
- JAVA 写文件操作
- java写文件操作
- Qt写文件操作
- 写文件操作
- PLSQL写文件操作
- 文件的写操作
- C++ 写文件操作
- 文件对象-写操作
- Python文件写操作
- 多线程写文件操作
- C#文件操作-写文件
- Android 文件操作 读/写
- python 读/写文件操作
- opencv去除高斯噪声(H1范数)
- go基础-函数
- SQL Server 数据类型部分汇总
- Java--集合--HashMap(1.8)
- POJ 3278 Catch That Cow(BFS+队列)
- 写文件操作探微
- JQuery 二级菜单联动,遍历($.each())
- 搭建intelj认证服务器
- 在android中使用intent来调用系统的应用中的删除功能
- docker常用命令
- 根据指定的元素删除数组中相同的元素
- 3-3 构造函数的调用(高级)
- run 参数
- 浅谈计算机系统架构