我一直在对 EL9 环境中的测试用例进行故障排除,该测试用例在 EL7 环境中的行为有所不同。
具体来说:
os.cwd()
返回“没有这样的文件或目录”。转载于:
复制代码示例:
#!/usr/bin/python3 -u
import os
import multiprocessing
import time
if __name__=="__main__":
multiprocessing.set_start_method("spawn")
count = 0
while True:
try:
os.getcwd()
pool = multiprocessing.Pool(10)
pool.close()
pool.terminate()
count += 1
except Exception as e:
print(f"Failed after {count} iterations")
print(e)
break
我有点不知所措,不明白这里发生了什么,以及它为什么会失败。
它似乎与
pool.terminate()
有关,就好像您在此之前添加哪怕是短暂的(0.05)睡眠,问题就会停止发生(至少,在“合理”的时间内无法重现,而上述方法在 <10 iterations). 中失败)
有趣的是
cwd
保持不一致:
build-2[myuser]:[~/python_race]$ ./simple.py
Failed after 2 iterations
[Errno 2] No such file or directory
build-2[myuser]:[~/python_race]$ ./simple.py
Traceback (most recent call last):
File "<frozen importlib._bootstrap_external>", line 1362, in _path_importer_cache
KeyError: '.'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./simple.py", line 4, in <module>
import multiprocessing
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 982, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 925, in _find_spec
File "<frozen importlib._bootstrap_external>", line 1423, in find_spec
File "<frozen importlib._bootstrap_external>", line 1392, in _get_spec
File "<frozen importlib._bootstrap_external>", line 1364, in _path_importer_cache
File "<frozen importlib._bootstrap_external>", line 1340, in _path_hooks
File "<frozen importlib._bootstrap_external>", line 1610, in path_hook_for_FileFinder
File "<frozen importlib._bootstrap_external>", line 1486, in __init__
FileNotFoundError: [Errno 2] No such file or directory
这似乎是通过 chdir 来“恢复”的,或者等待我认为是 NFS 缓存到期间隔的时间。
我们之所以选择这个,是因为我们的一些测试在“新版本”上失败了,更简单:
import multiprocessing
multiprocessing.set_start_method("spawn")
while True:
multiprocessing.Pool(10)
但正如前面提到的 - 特定于 NFS 挂载在子目录中,我们认为这可能是因为
struct dentry
在根挂载上的行为有点不同。
但我想知道是否有人可以深入了解这里可能出了什么问题?我不知道它是否可能是文件服务器、Linux 内核、Python 中的某些东西,或者……好吧,完全是其他地方。
启用 rpcdebug 后,我们似乎得到:
Apr 24 11:58:47 build-2 kernel: NFS: release(lib/libgcc_s.so.1)
Apr 24 11:58:47 build-2 kernel: NFS: release(lib/libc.so.6)
Apr 24 11:58:47 build-2 kernel: NFS: release(locale/locale-archive)
Apr 24 11:58:47 build-2 kernel: NFS reply getattr: -512
Apr 24 11:58:47 build-2 kernel: nfs_revalidate_inode: (0:53/3834468196) getattr failed, error=-512
Apr 24 11:58:47 build-2 kernel: NFS: lookup(/python_race)
Apr 24 11:58:47 build-2 kernel: NFS call lookup /python_race
Apr 24 11:58:47 build-2 kernel: RPC: xs_tcp_send_request(168) = 0
Apr 24 11:58:47 build-2 kernel: NFS: release(bin/python3.11)
编辑:
还发现,如果您在 pool.join()
之前添加
terminate()
,则不会发生
这并不是一个真正的答案,而是确认它实际上是一个内核错误,而不是一个 python 问题 - 碰巧 python 是一种“触发”它的简单方法。
使用 RedHat 登录:https://issues.redhat.com/browse/RHEL-35853
如果有人遇到同样的问题,我们发现添加:
pool.join()
在
pool.terminate()
之前进入代码似乎阻止了它的发生,但考虑到问题是在内核空间中,我们不相信它比“只是”代码中的短暂延迟更实质性,这掩盖了隐式竞争状况。
我们发现,
sleep(0.05)
同样似乎可以防止这种情况发生,大概是出于类似的原因,因为用户空间不可能首先使目录条目缓存无效。