使用 `with:` 语句的 Python 文件锁模块行为

Posted

技术标签:

【中文标题】使用 `with:` 语句的 Python 文件锁模块行为【英文标题】:Python filelock module behavior using `with:` statement 【发布时间】:2017-06-15 04:56:23 【问题描述】:

我只是想知道 python 模块文件锁的细节及其在某些情况下的行为。

首先,线程如何处理with: 语句。如果多个线程调用with:,它是逐个线程锁定的吗?是否也有可能两个线程同时获取锁?

其次,当我使用with: 时,我必须在使用后清除锁定吗? with:语句执行完后锁会自动清零吗?

第三,我的代码中有一个实例,我认为必须创建一个文件然后立即锁定。目前我正在使用这个:

channel_file = open(os.path.join('channels', username), 'w+')
with filelock.FileLock(os.path.join('channels', username)):
  channel_file.write(json.dumps('rate': reobj.group(1),'time': reobj.group(2)))

如果有可能另一个线程从文件创建时就可以读取该文件,这是否可以防止这种情况发生?

这也带来了第四点。使用with:时文件锁是否会锁定读取访问权限?

【问题讨论】:

【参考方案1】:

    FileLock 维护一个锁计数器,该计数器在进程中的所有线程之间共享,并受到线程锁的保护。每次调用acquire() 都会增加锁计数器,并在计数器为零时额外获得操作系统级别的文件锁。同样,每次调用release() 都会减少锁定计数器并在计数器达到零时解锁文件。

    因此,如果两个线程同时获得锁,则该文件将在操作系统级别被该进程锁一次,锁计数器将增加2。两个线程不会互相阻塞。

    with:的重点是在其作用域退出后自动获取和释放锁。见What is the python "with" statement designed for?。

    文件锁用于防止当前进程之外的文件访问。它不用于线程锁定。使用常规的threading.Lock 进行线程锁定。

    # in __main__ or somewhere before we start the threads.
    channel_lock = threading.Lock()
    
    # in the worker thread
    with channel_lock:
        with open(...) as channel_file:
            channel_file.write(...)
    

实现细节可以参考source code of py-filelock

【讨论】:

以上是关于使用 `with:` 语句的 Python 文件锁模块行为的主要内容,如果未能解决你的问题,请参考以下文章

Python 的with语句

上下文管理器——with语句的实现

python中with语句的作用

Python高级详解with语句和上下文管理器

Python高级详解with语句和上下文管理器

Python新手,怎么使用with语句?对于with语句及其用法都有哪些