我有一个脚本,该脚本使用非常简单的基于IPC的文件与另一个程序进行通信。我编写了一个包含新内容的tmp文件,并将其mv
放在IPC文件上,以使内容保持原子状态(另一个程序侦听重命名事件)。
但是现在有个问题:这相当于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程序之前,它一直保持打开状态。连续运行会按预期方式更改内容,索引节点和文件描述符,但仍会打开
mv
所不希望的内容。当包含以上这些行的python程序被关闭时,文件最终被关闭。
编辑:
发现了错误:
tempfile.mkstemp()
处理不当。参见:https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp我像这样创建了临时文件:
_fd, temp_file_path = tempfile.mkstemp()
我丢弃了默认打开的filedescriptor
_fd
。我没有关闭它,因此即使在移动后它也保持打开状态。这导致了一个打开的目标,并且由于我只是在该目标上lsof
,所以我没有看到临时文件已经打开。这将是正确的版本:fd, temp_file_path = tempfile.mkstemp()
fd.write(content)
fd.close()
# ... mv/rename via shell execution/shutil/pathlib
非常感谢大家的帮助和建议!
最佳答案
我无法重现此行为。我创建了一个文件/tmp/tempfile
,并通过您给出的subprocess.run
调用运行了python脚本,然后进行了长时间的睡眠。没有使用/tmp/target
,也没有在lsof -p <pid>
中看到任何意外打开的文件。
(编辑)对此我并不感到惊讶,因为您的子进程命令无法打开文件: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)
在这种情况下,该文件仍处于打开状态,因为它从未关闭过,即使已被重命名,原始文件句柄仍然存在。我敢打赌,您的代码中有一些类似的东西正在创建此文件并为其打开句柄。
关于python - Python 3:subprocess.run('mv')使目标保持打开状态,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55496679/