Python 3:子流程运行('mv')使目标打开

2024-04-26 07:42:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个脚本,它使用一个非常简单的基于文件的IPC与另一个程序通信。我用新内容编写一个tmp文件,并mv将其保存到IPC文件中,以保存atomar(另一个程序侦听重命名事件)。你知道吗

但现在的问题来了:这种方法可以工作2到3次,但之后交换就卡住了。你知道吗

time.sleep(10)
# check lsof => target file not opened
subprocess.run(
    "mv /tmp/tempfile /tmp/target",
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    universal_newlines=True,
    shell=True,
)
# check lsof => target file STILL open
time.sleep(10)

/tmp/tempfile将为每次写入做好准备

第一次运行的结果是:

$ lsof /tmp/target
COMMAND  PID        USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
python  1714      <user>   3u   REG   0,18      302 10058 /tmp/target

在我终止python主程序之前保持打开状态。连续运行会像预期的那样更改内容、inode和文件描述符,但它仍然是打开的,这是我不希望从mv中看到的。你知道吗

当包含以上这些行的python程序被关闭时,文件最终被关闭。你知道吗

编辑:

发现错误:错误处理tempfile.mkstemp()。见:https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp

我创建了tempfile,如下所示:

_fd, temp_file_path = tempfile.mkstemp()

在这里,我丢弃了filedescriptor_fd,它在默认情况下是打开的。我没有关上它,所以即使在搬家后它仍然开着。这导致了一个打开的目标,因为我只是在目标上lsof,我没有看到tempfile已经打开了。这将是正确的版本:

fd, temp_file_path = tempfile.mkstemp()
fd.write(content)
fd.close()

# ... mv/rename via shell execution/shutil/pathlib

非常感谢大家的帮助和建议!你知道吗


Tags: 文件程序内容targettimesleeptempfiletmp
3条回答

有什么理由不使用shutil.move?否则,可能需要等待mv命令完成移动,然后杀死它,读取stdin,运行类似

p = subprocess.run(...)
# wait to finish moving/read from stdin
p.terminate()

当然terminate会有点苛刻。你知道吗

Edit:根据您的使用情况,rsync不是python的一部分,它可能是一个优雅的解决方案,可以在网络上保持数据同步,而无需编写一行代码

您说它仍然是由“mv”打开的,但您不知道python显示的结果是如何打开的。由于它是一个子进程,请查看pid是否与python进程相同,可能是另一个python进程。你知道吗

我无法重现这种行为。我创建了一个文件/tmp/tempfile,并运行了一个python脚本,其中包含subprocess.run调用,然后是长时间睡眠。/tmp/target没有被使用,也没有在lsof -p <pid>中看到任何意外打开的文件。你知道吗

(edit)我对此并不感到惊讶,因为您的subprocess命令不可能打开文件:mv不打开它的参数(您可以用ltrace检查它),并且subprocess.run不解析它的参数或对它做任何操作,除了将它传递给exec-ed之外

但是,当我添加一些行来打开一个文件并对其进行写入,然后移动该文件时,我看到的行为与您描述的相同。代码如下:

import subprocess
out=open('/tmp/tempfile', 'w')
out.write('hello')
subprocess.run(
    "mv /tmp/tempfile /tmp/target",
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    universal_newlines=True,
    shell=True,
)
import time
time.sleep(5000)

在这种情况下,文件仍然处于打开状态,因为它从未关闭过,而且即使已重命名,原始文件句柄仍然存在。我敢打赌,您的代码中有类似的东西,创建这个文件并为它留下一个打开的句柄。你知道吗

相关问题 更多 >