前言

Python语言中的文件锁可以使用 fcntl 库,它实际上是对Unix系统上的 fcntlioctl 函数提供了一个接口。官网描述中是这样形容的:

This module performs file control and I/O control on file descriptors

这个模块提供了针对文件描述符的文件控制和I/O控制。常用的是在多进程/线程读写同一文件时需要使用的文件锁功能。

模块函数

· fcntl.fcntl(fd, cmd, arg=0)
· fcntl.ioctl(fd, request, arg=0, mutate_flag=True)
· fcntl.flock(fd, operation)
· fcntl.lockf(fd, cmd, len=0, start=0, whence=0)

自己暂时只用到了 fcntl.flock 这个函数对文件上锁,在此做一些记录。

使用

考虑两个进程对同一个文件进行读写操作:
目录下有一个test.json文件内容如下:

{"test1": {"1000": {"files": "5"},"1001": {"files": "6"}},"test2": {"2000": {"files": "0"},"2001": {"files": "1"}}
}

处理代码如下,模拟两个进程对该文件进行写操作:

import json
import time
import fcntl
import multiprocessing as mptest_dict = {"test1": {"1001": {"files": "6"}},"test2": {"2000": {"files": "0"},"2001": {"files": "1"}}
}def test1(json_path):with open(json_path, 'r+') as test_file:fcntl.flock(test_file.fileno(), fcntl.LOCK_EX) #加锁,with块外自动释放锁json_content = test_dict# time.sleep(5)test_file.truncate()#手动清空json.dump(json_content, test_file, sort_keys=True, indent=4, separators=(',', ': '))def test2(json_path):with open(json_path, 'r+') as test_file:fcntl.flock(test_file.fileno(), fcntl.LOCK_EX)test_dict['test1'][str(3001)] = {"files":str(7)}json_content = test_dicttest_file.truncate()json.dump(json_content, test_file, sort_keys=True, indent=4, separators=(',', ': '))if __name__ == '__main__':json_path = r'./test.json'p = mp.Process(target=test1, args=(json_path,))q = mp.Process(target=test2, args=(json_path,))p.start()q.start()p.join()q.join()

分析:
进程p先启动后获取到文件锁,以r+模式打开test.json文件,使用with...open...打开时文件内容不会清空,所以在多进程读写同一文件时需要特别注意文件的打开方式。在写入前使用truncate()函数手动清空内容,最终文件内容如下:

{"test1": {"1001": {"files": "6"}},"test2": {"2000": {"files": "0"},"2001": {"files": "1"}}
}

进程q后启动,在with...open...后希望获取文件锁,此时如果进程p打开的文件还未处理结束,文件锁还未释放之前,q会一直处于阻塞状态。直到进程pwith...open...代码块结束后文件锁自动释放(也可以选择手动释放文件锁),进程q才获取到文件锁,开始往test.json文件中写入内容。最终文件内容如下:

{"test1": {"1001": {"files": "6"},"3001": {"files": "7"},},"test2": {"2000": {"files": "0"},"2001": {"files": "1"}}
}

两个进程读写同一文件,假设进程p先启动先获得文件锁,进程q后启动后获得文件锁:

进程p 进程q 说明
p读到旧文件内容后释放锁,q获得锁后写新内容到文件
不涉及文件内容修改,均读到同样的文件内容
p写新内容到文件后释放锁,q获得锁后读到新文件内容
p写新内容到文件后释放锁,q获得锁后写新内容到文件

多进程读写同一文件时均需要考虑加锁,否则会出现异常情况。例如在进程p获得文件锁后正在写文件,进程q不考虑加锁直接读取该文件,可能会由于文件内容被进程p清空(包括“以w模式打开时清空”和“以truncate()方式清空”)导致读取出错。当读取操作也加锁时,如果进程p未结束文件锁未被释放,那么进程q将一直等待,直到得到锁后读取文件,这时不会出错。

总结:
(1)在打开一个文件时,以w模式和以r+模式打开时表现不同。其中以w模式打开时会清空文件内容,写入时是将新内容写入文件;以r+模式打开时不会清空文件内容,写入时是从游标0处写入新内容,但旧内容如果长于新内容,则会出现未被覆盖掉的旧内容,导致内容出错。需要特别注意。
(2)文件锁不要长期占用,处理结束后尽快释放掉。
(3)多进程读写同一文件时避免以w(以及w+等)模式打开文件,否则打开瞬间文件内容即被清空。
(4)加文件锁写json的代码:

def server_json_dump(json_content, json_path):"""写json"""if os.path.exists(json_path):mode = 'r+'#以r+模式打开避免with...open打开文件时自动清空内容同时被读取else:mode = 'w'#以w模式打开以新建文件with open(json_path, mode=mode) as result_file:#以r+形式打开fcntl.flock(result_file.fileno(), fcntl.LOCK_EX) #加锁,with块外自动释放锁result_file.truncate()#手动清空,避免r+模式下文本重叠json.dump(json_content, result_file, sort_keys=True, indent=4, separators=(',', ': '))

参考资料

[1] fcntl — The fcntl and ioctl system calls
[2] Python 标准库之 fcntl
[3] Python open函数
[4] Python清空文件并替换内容
[5] 文件锁 python 进程间锁 fcntl

Python使用fcntl文件锁相关推荐

  1. python 的fcntl模块

    python 中给文件加锁--fcntl模块 import fcntl 打开一个文件 f = open('./test') ##当前目录下test文件要先存在,如果不存在会报错. 对该文件加密: fc ...

  2. python怎么加锁_python使用fcntl模块实现程序加锁的方法

    python使用fcntl模块实现程序加锁功能示例 本文实例讲述了python使用fcntl模块实现程序加锁功能.分享给大家供大家参考,具体如下: python 中引入给文件加锁的 fcntl模块 i ...

  3. Linux 系统 文件锁 fcntl函数详解

    #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int ...

  4. Linux 文件锁 fcntl 函数详解

    Linux 文件锁 fcntl 函数详解 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); ...

  5. python 多线程多进程logging系统写入同一日志文件处理方法

    多线程进程,logging写入日志到同一文件的处理方法 python logging系统切分问题 TimedRotatingFileHandler切分逻辑源码 解决方案 python logging系 ...

  6. 在Python中对子进程进行非阻塞读取

    我正在使用子流程模块来启动子流程并连接到其输出流(stdout). 我希望能够在其stdout上执行非阻塞读取. 有没有一种方法可以使.readline成为非阻塞状态,或者在调用.readline之前 ...

  7. linux fcntl 函数 文件描述符选项控制

    功能描述:根据文件描述词来操作文件的特性. #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); ...

  8. linux fcntl注销信号,linux下fcntl的使用(转载)

    功能描述:根据文件描述词来操作文件的特性. #include #include  int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long ...

  9. C Linux 文件加锁 lock fcntl

    Linux系统中,文件上锁的函数有两个Lock和fcntl ,前者主要是加建议性锁,后者既可以加建议性锁(默认)也可以加强制性锁,而且她还可以给某一记录进行上锁,即所谓的记录锁. fcntl文件锁有两 ...

最新文章

  1. Hadoop源代码分析 - MapReduce(转载)
  2. C 语言运算符优先级
  3. CTF Geek Challenge——第十一届极客大挑战Web Write Up
  4. Boost:用成员函数测试bind <void>
  5. 01_GIT基础、安装
  6. 用ORACHK自己主动化检查数据库系统的健壮性
  7. 如何从服务器导出文件,如何从云服务器导出文件
  8. php铺满,重复铺满水印 - Jun. - OSCHINA - 中文开源技术交流社区
  9. indexOf与includes的区别
  10. XFire 配置文件注意事项
  11. 信号与噪声经过匹配滤波器后能量
  12. 斐讯K2 新版固件刷机教程
  13. JAVA面试问题及答案
  14. SQLyog 报错2058 :连接 mysql 8.0.11 解决方法
  15. 数字化门店管理|如何让门店数字化管理,更加贴合日常运营细节?
  16. kafka connector 使用总结以及自定义connector开发
  17. 水岸秀墅|千年石湖独一墅
  18. Centos7.9上利用cephadm安装Ceph Octopus 15.2的采坑记录,附带K8S挂载方法
  19. camera打开闪光灯页面崩溃 android,Android打开闪光灯关键代码
  20. python爬虫和办公自动化培训班

热门文章

  1. 汽车配置名词解释(5):座椅及车身配置
  2. 分享汽车保险杠内分型
  3. html input 禁止输入中文
  4. 单精度浮点数的取值,表示以及相关
  5. 七牛云存储挂载到阿里云ECS上的目录下,达到扩容磁盘的效果
  6. ios8新特性widget开发(手机上和通知栏并列的今天的制作)
  7. jquery 自适应轮播图
  8. zabix监控linux进程名称,zabbix监控linux进程及服务通用key方式
  9. kali之httrac:复制网站
  10. 读《敏捷无敌之DevOps时代》有感