迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Python >

在 Python 中锁定文件

作者:迹忆客 最近更新:2023/04/26 浏览次数:

在我们的日常生活中,有些资源是不能被两个人同时访问的,比如更衣室。 每个更衣室都有一把锁,一次只有一个人可以打开。

如果两个人同时访问,可能会造成混乱和尴尬。 所以,这就是共享资源受到锁保护的原因。

同样,在编程中,只要两个进程或线程共享同一资源,就会产生必须使用锁来避免的问题。 本文将解释如何在 Python 中锁定文件。


Python中多进程共享资源的影响

本节将阐明为什么在 Python 中锁定文件很重要。

该程序有两个过程:第一个向帐户中存入$1,另一个从中扣除$1,最后打印余额。 此操作在循环内运行数千次。

从技术上讲,迭代不会导致最终余额发生变化,因为一遍又一遍地添加和扣除相同的数字。 但是当程序被编译时,结果是可变的。

import multiprocessing

# Withdrawal function

def wthdrw(bal):
    for _ in range(10000):
        bal.value = bal.value - 1


# Deposit function

def dpst(bal):
    for _ in range(10000):
        bal.value = bal.value + 1


def transact():
    # initial balance
    bal = multiprocessing.Value('i', 100)

    # creating processes
    proc1 = multiprocessing.Process(target=wthdrw, args=(bal,))
    proc2 = multiprocessing.Process(target=dpst, args=(bal,))

    # starting processes
    proc1.start()
    proc2.start()

    # waiting for processes to finish
    proc1.join()
    proc2.join()

    # printing final balance
    print("Final balance = {}".format(bal.value))


if __name__ == "__main__":

    for _ in range(10):
        # Performing transaction process
        transact()

输出:

C:\python38\python.exe "C:\Users\Win 10\main.py"
Final balance = 428
Final balance = 617
Final balance = -1327
Final balance = 1585
Final balance = -130
Final balance = -338
Final balance = -73
Final balance = -569
Final balance = 256
Final balance = -426

Process finished with exit code 0

让我们分解示例代码以了解它发生的原因。

该程序使用 Python 库包 multiprocessing 将方法作为程序中的进程调用。

wthdrw 和 dpst 这两个方法,在账户中扣钱和加钱。 它们有一个参数,bal,代表平衡。

在方法内部,bal 的值在 for 循环内递增或递减。 迭代重复 10000 次。

bal.value 是这个程序中的共享资源。

# Method to Decrement
def wthdrw(bal):
    for _ in range(10000):
        bal.value = bal.value - 1

一种新的方法 transact() 可以一个接一个地启动进程。 在该方法内部,创建了存储初始值的对象 bal,并将余额设置为 100。

def transact():
    bal = multiprocessing.Value('i', 100)
    lock = multiprocessing.Lock()

multiprocessing 库允许使用对象将方法作为进程启动。 例如,方法 wthdrw 是通过创建进程 proc1 来启动的。

此过程以 wthdrw 方法为目标,并将 bal 和一个空对象作为参数传递。

proc1 = multiprocessing.Process(target=wthdrw, args=(bal,))

同样,创建一个 proc2 进程来启动 dpst 方法。 创建两个进程后,将使用 process_name.start() 启动它们。

proc1.start()
proc2.start()

要关闭正在运行的进程,使用 process_name.join() 语法。 它将请求排在正在运行的进程后面,因此系统会等待进程完成,然后将其关闭。

过程完成后打印最终余额。

print("Final balance = {}".format(bal.value))

__name__ 变量设置为 __main ,并在 for 循环内调用方法 transact()。 这让我们可以多次观察迭代,而无需手动调用流程。

if __name__ == "__main__":

    for _ in range(10):
        transact()

当程序运行时,我们发现数值不一致。 共享资源 bal.value 不受锁保护,因此其他进程在运行进程完成之前编辑该值。

锁就是用来解决这个问题的。 上面的程序通过在两种方法中放置一个锁来锁定; 这样,编译器必须等待在前一个进程完成之前运行下一个进程。

# Withdrawal function
def wthdrw(bal, lock):
    for _ in range(10000):
        # Locks
        lock.acquire()
        bal.value = bal.value - 1
        lock.release()

lock.acquire() 语句锁定进程,并在其中编辑 bal 的值。 之后,使用 lock.release() 释放锁。

这同样适用于 dpst 方法,程序的其余部分保持不变。

输出:

C:\python38\python.exe "C:\Users\Win 10\main.py"
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100

Process finished with exit code 0

正如我们知道共享资源的多个进程会发生什么,我们将研究在 Python 中锁定文件所需的重要功能 - 文件状态。


文件状态及其对 Python 中锁定文件的影响

文件状态显示文件是打开还是关闭。 了解文件状态以在 Python 中锁定文件很重要,因为锁定操作只能放在打开的文件上。

在 Python 中,假设有一个文件——“myFile.txt”。 当我们写:

readMyFile=open("myFile.txt","r").read()

无法获取文件的状态、关闭它或执行任何其他操作。 没有访问权限,因为它没有存储在任何地方。

由于丢弃信息没有任何价值,而且垃圾收集是不可能的,所以没有魔法可以让丢失的知识恢复。

避免存储任何打算在变量(列表、字典成员或实例的属性)中使用的值,这将允许使用它。

myFile = open("myFile.txt", "r")
readMyFile = myFile.read()
print(myFile.closed)

myFile.close()
print(myFile.closed)

上面的代码将文件保存在变量 myFile 中。 然后另一个变量 readMyFile 使用 myFile 变量读取对象。

即使在读取完成后,使用此方法也会使文件保持打开状态。

语法 print(myFile.closed) 显示当前文件状态; 在这里,它返回一个假值,这意味着它没有关闭。 使用 myFile.close() 显式关闭此文件。

由于显式关闭文件容易导致人为错误,更好的解决方案是使用 with 语句。

with open("myFile.txt", "r") as myFile:
     readMyFile = myFile.read()

现在,myFile 会自动关闭而无需显式关闭它。 从上面的示例中,我们了解到打开和关闭文件的有效方法对于在 Python 中锁定文件至关重要。

文件只能在打开状态下被锁定,没有锁时无法解锁文件。 在 Python 中锁定文件必须始终在 with 块内执行。

让我们看看在 python 中锁定文件的几种方法。


在 Python 中锁定文件

文件锁通常是在脚本内部使用的第三方库来锁定文件。 在本节中,将讨论一些广泛使用的文件锁。

在 Python 中使用 FileLock 锁定文件

这是一个特定于平台的文件锁定库,可在 Windows 和 UNIX 上运行。 要安装它,请键入命令:

pip install filelock

使用此方法锁定文件非常简单。 在 with 语句中使用 FileLock 打开文件,因此文件打开,系统将其锁定。

处理完成后,在 with 语句结束时自动释放锁。

from filelock import FileLock

with FileLock("myfile.txt"):
    print("Lock acquired.")

输出:

C:\python38\python.exe "C:/main.py"
Lock acquired.

Process finished with exit code 0

在 Python 中锁定文件的另一种方法是使用超时。 如果无法锁定文件,这有助于设置时间限制,从而释放其他进程的文件句柄。

from filelock import FileLock
file = "example.txt"
lockfile = "example.txt.lock"

lock = FileLock(lockfile, timeout=5)

lock.acquire()
with open(file, "a") as f:
    print("File Locked")
    f.write("Add some data \n")
lock.release()


with open(file, "a") as f:
    f.write("Second time writing \n")

第一行代码从文件锁库中导入文件锁模块。 example.txt 文件保存在一个变量文件中; 该文件将用于在其上写入。

锁没有直接放在原始文件上,因此创建了一个临时文件,如 example.txt.lock。 变量lock用于为lockfile创建一个锁对象,设置超时时间为5秒。

可以使用 lock.acquire 语句放置此锁。 with 块用于打开文件并写入文件,而 lockfile 避免任何其他进程在写入时访问原始文件。

最后,使用 lock.release() 释放锁。 然后另一个进程打开文件并成功写入。

输出:

C:\python38\python.exe "C:/main.py"
File Locked

Process finished with exit code 0

Python 使用 FileLock 锁定文件 - 输出

要使用 Python 锁定文件,我们还可以以嵌套方式放置锁:

from filelock import Timeout, FileLock

lock = FileLock("high_ground.txt.lock")
with lock:
    with open("high_ground.txt", "a") as f:
        f.write("You were the chosen one.")

在上面的示例中,使用名为 high_ground.txt 的文件创建了一个锁定对象,以锁定 Python 中的一个文件。 锁放在一个块内; 在其中,使用另一个块读取文件。

这种方法比前一种方法需要更少的代码。

FileLock 是平台相关的。 如果每个应用程序实例都在同一平台上运行,请使用 FileLock; 否则,使用 SoftFileLock。

SoftFileLock 独立于平台,只监视锁定文件的存在。 正因为如此,它非常便携,并且在应用程序崩溃时更有可能死机。

在这种情况下,请删除锁定文件。

文件储物柜也可以与异常处理块一起使用:

try:
    with lock.acquire(timeout=10):
        with open(file_path, "a") as f:
            f.write("I have a bad feeling about this.")
except Timeout:
    print("Another instance of this application currently holds the lock.")

此代码片段在 try 块内放置了一个锁,并给出了 10 秒的超时。 然后在一个嵌套的里面,文件被写入。

在 except 块内,如果应用程序超时,将打印一条合适的消息。

在 Python 中使用 PortaLocker 锁定文件

在 Python 中锁定文件的另一种选择是使用名为 portalocker 的库,它提供了一个简单的文件锁定 API。

重要的是要记住,锁在 Linux 和 Unix 系统上默认是建议性的。 通过在 mount 命令中添加 -o mand 选项,可以在 Linux 上启用强制文件锁定。

要安装它,请键入命令:

pip install "portalocker[redis]"

使用 portalocker 在 Python 中锁定文件类似于 FileLock 方法,但更简单。

import portalocker

file = 'example.txt'
with portalocker.Lock(file, "a") as fh:
    fh.write("first instance")
    print('waiting for your input')
    input()

输出:

C:\python38\python.exe "C:/main.py"

lock acquired
waiting for your input

在上面的代码中,第一行导入了库包。 使用语法 portalocker.RedisLock() 创建锁,并使用 with 语句放置锁。

要将锁置于超时内,请使用:

import portalocker
file = 'example.txt'
with portalocker.Lock('file', timeout=1) as fh:
    print('writing some stuff to my cache...', file=fh)

输出:

使用 PortaLocker 的 Python 锁定文件 - 输出


总结

本文解释了如何在 Python 中锁定文件及其重要性。 阅读本文后,大家可以轻松创建开放状态文件并对其进行锁定。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Django 中的 Slug

发布时间:2023/05/04 浏览次数:173 分类:Python

本篇文章旨在定义一个 slug 以及我们如何使用 slug 字段在 Python 中使用 Django 获得独特的帖子。

Django ALLOWED_HOSTS 介绍

发布时间:2023/05/04 浏览次数:181 分类:Python

本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。

Django 中的 Select_related 方法

发布时间:2023/05/04 浏览次数:129 分类:Python

本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。

在 Django 中上传媒体文件

发布时间:2023/05/04 浏览次数:198 分类:Python

在本文中,我们简要介绍了媒体文件以及如何在 Django 项目中操作媒体文件。

Django 返回 JSON

发布时间:2023/05/04 浏览次数:106 分类:Python

在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。

在 Django 中创建对象

发布时间:2023/05/04 浏览次数:59 分类:Python

本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。

在 Django 中为多项选择创建字段

发布时间:2023/05/04 浏览次数:75 分类:Python

在本文中,我们将着眼于为多项选择创建一个字段,并向您展示如何允许用户在 Django 中进行多项选择。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便