当进程被终止时,Python 中的文件对象是如何清理的?
How are file objects cleaned up in Python when the process is killed?
当进程终止时,Python 中的文件对象会发生什么情况? Python 是否以 SIGTERM
、SIGKILL
、SIGHUP
(等)或 KeyboardInterrupt
异常终止是否重要?
我有一些日志记录脚本可以持续获取数据并将其写入文件。我不关心做任何额外的清理,但我只是想确保当 Python 突然终止时日志文件没有损坏(例如,我可以将它 运行 留在后台并且只是关闭计算机)。我制作了以下测试脚本来尝试看看会发生什么:
termtest.sh
:
for i in $(seq 1 10); do
python termtest.py $i & export pypid=$!
sleep 0.3
echo $pypid
kill -SIGTERM $pypid
done
termtest.py
:
import csv
import os
import signal
import sys
end_loop = False
def handle_interrupt(*args):
global end_loop
end_loop = True
signal.signal(signal.SIGINT, handle_interrupt)
with open('test' + str(sys.argv[-1]) + '.txt', 'w') as csvfile:
writer = csv.writer(csvfile)
for idx in range(int(1e7)):
writer.writerow((idx, 'a' * 60000))
csvfile.flush()
os.fsync(csvfile.fileno())
if end_loop:
break
I 运行 termtest.sh
具有不同的信号(将 SIGTERM
更改为 SIGINT
、SIGHUP
和 [=17= 中的 SIGKILL
])(注意:我在 termtest.py
中为 SIGINT
放置了一个显式处理程序,因为 Python 除了 Ctrl+C
之外不处理那个处理程序)。在所有情况下,所有输出文件都只有完整的行(没有部分写入)并且没有出现损坏。我调用 flush()
和 fsync()
来尝试确保数据尽可能多地写入磁盘,以便脚本在写入过程中被中断的可能性最大。
那么我是否可以得出这样的结论:Python 总是在终止时完成写入并且不会将文件留在中间状态?或者这是否取决于操作系统和文件系统(我正在测试 Linux 和一个 ext4 分区)?
重要的不是文件是如何 "cleaned up" 而是文件是如何写入的。一个程序可能会对单个 "chunk" 数据(行或其他)执行多次写入,并且您可能会在此过程中间中断并最终写入部分记录。
查看 csv
模块的 C source,它将每一行组装到一个字符串缓冲区,然后使用单个 write()
调用写入。这通常应该是安全的;该行要么被传递给 OS,要么没有传递给 OS,如果它到达 OS,它就会被写入,或者不会(当然,除了硬件问题,其中一部分可能会被写入)进入坏扇区)。
writer 对象是一个 Python 对象,自定义 writer 可以在其 write()
中做一些奇怪的事情来破坏它,但假设它是一个常规文件对象,它应该没问题。
当进程终止时,Python 中的文件对象会发生什么情况? Python 是否以 SIGTERM
、SIGKILL
、SIGHUP
(等)或 KeyboardInterrupt
异常终止是否重要?
我有一些日志记录脚本可以持续获取数据并将其写入文件。我不关心做任何额外的清理,但我只是想确保当 Python 突然终止时日志文件没有损坏(例如,我可以将它 运行 留在后台并且只是关闭计算机)。我制作了以下测试脚本来尝试看看会发生什么:
termtest.sh
:
for i in $(seq 1 10); do
python termtest.py $i & export pypid=$!
sleep 0.3
echo $pypid
kill -SIGTERM $pypid
done
termtest.py
:
import csv
import os
import signal
import sys
end_loop = False
def handle_interrupt(*args):
global end_loop
end_loop = True
signal.signal(signal.SIGINT, handle_interrupt)
with open('test' + str(sys.argv[-1]) + '.txt', 'w') as csvfile:
writer = csv.writer(csvfile)
for idx in range(int(1e7)):
writer.writerow((idx, 'a' * 60000))
csvfile.flush()
os.fsync(csvfile.fileno())
if end_loop:
break
I 运行 termtest.sh
具有不同的信号(将 SIGTERM
更改为 SIGINT
、SIGHUP
和 [=17= 中的 SIGKILL
])(注意:我在 termtest.py
中为 SIGINT
放置了一个显式处理程序,因为 Python 除了 Ctrl+C
之外不处理那个处理程序)。在所有情况下,所有输出文件都只有完整的行(没有部分写入)并且没有出现损坏。我调用 flush()
和 fsync()
来尝试确保数据尽可能多地写入磁盘,以便脚本在写入过程中被中断的可能性最大。
那么我是否可以得出这样的结论:Python 总是在终止时完成写入并且不会将文件留在中间状态?或者这是否取决于操作系统和文件系统(我正在测试 Linux 和一个 ext4 分区)?
重要的不是文件是如何 "cleaned up" 而是文件是如何写入的。一个程序可能会对单个 "chunk" 数据(行或其他)执行多次写入,并且您可能会在此过程中间中断并最终写入部分记录。
查看 csv
模块的 C source,它将每一行组装到一个字符串缓冲区,然后使用单个 write()
调用写入。这通常应该是安全的;该行要么被传递给 OS,要么没有传递给 OS,如果它到达 OS,它就会被写入,或者不会(当然,除了硬件问题,其中一部分可能会被写入)进入坏扇区)。
writer 对象是一个 Python 对象,自定义 writer 可以在其 write()
中做一些奇怪的事情来破坏它,但假设它是一个常规文件对象,它应该没问题。