我遇到了一个奇怪的错误,很多人似乎是在完全不同的情况下发生的。在我发现的情况下,它主要与mkdir
一起使用文件所在的路径被调用有关。
但就我而言,我只是在现有文本文件上调用open("meta.yml", "r")
。堆栈跟踪明确指向仅调用open
的行,具体来说
File "some-path/experiment.py", line 348, in deserialize
with open("meta.yml", "r") as f:
FileExistsError: [Errno 17] File exists: 'meta.yml'
函数本身很简单
def deserialize() -> "Experiment":
with open("meta.yml", "r") as f:
contents = f.read()
obj = yaml.load(contents, Loader=yaml.Loader)
# ...
并且错误发生在open
调用的行上。
我非常确定文件存在,并且没有相同名称的目录。 需要注意的重要一点是,这不会在100%的时间内失败。我本质上是在循环中执行代码(中间有几秒钟的睡眠),这需要相当长的时间。同时发生例外。没有其他进程可以访问此文件,到目前为止,每次让它运行一段时间(例如一个小时),我都会失败(有时更快)。
我设法通过strace运行了故障,这是故障之前的最后几个电话
openat(AT_FDCWD, "/proc/37871/stat", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
ioctl(4, TCGETS, 0x7ffcabed25a0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(4, 0, SEEK_CUR) = 0
lseek(4, 0, SEEK_CUR) = 0
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(4, "37871 (polkitd) S 1 37871 37871 "..., 8192) = 175
read(4, "", 8017) = 0
close(4) = 0
select(0, NULL, NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)
openat(AT_FDCWD, ".lockfile", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0777) = 4
flock(4, LOCK_EX|LOCK_NB) = 0
openat(AT_FDCWD, "meta.yml", O_RDONLY|O_CLOEXEC) = -1 EEXIST (File exists) # <- here it fails
flock(4, LOCK_UN) = 0
close(4) = 0
如您所见,openat
返回带有句柄-1的EEXIST
。有趣的是,在相同的跟踪中,在相同的系统调用成功返回之前发生了60次。这是一个例子
select(0, NULL, NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)
openat(AT_FDCWD, ".lockfile", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0777) = 4
flock(4, LOCK_EX|LOCK_NB) = 0
openat(AT_FDCWD, "meta.yml", O_RDONLY|O_CLOEXEC) = 5 # <- here it's ok
fstat(5, {st_mode=S_IFREG|0664, st_size=5194, ...}) = 0
ioctl(5, TCGETS, 0x7ffcabed2ec0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(5, 0, SEEK_CUR) = 0
ioctl(5, TCGETS, 0x7ffcabed2ea0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(5, 0, SEEK_CUR) = 0
lseek(5, 0, SEEK_CUR) = 0
fstat(5, {st_mode=S_IFREG|0664, st_size=5194, ...}) = 0
read(5, "gp_config: !!python/object:bopt."..., 5195) = 5194
read(5, "", 1) = 0
close(5) = 0
基于手册页,我不知道这怎么可能发生。可能值得注意的是,尽管文件只能从单个计算机上的单个进程访问,但它位于网络文件系统上。