Я устранял неполадки в тестовом примере в среде 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 итераций) .
И что интересно, 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()
.
Это полезная информация — да, у меня есть подозрение, что здесь есть «что-то» пересекающееся с NFS/EL9/Python. Не могли бы вы сообщить мне, какое у вас ядро?
macOS Sonoma 14.4.1 с Python 3.12.3
На самом деле это не ответ-ответ, а подтверждение того, что на самом деле это ошибка ядра, а не проблема Python - так уж получилось, что Python был простым способом «запустить» ее.
Зарегистрировано с помощью RedHat: https://issues.redhat.com/browse/RHEL-35853
Если кто-то сталкивается с той же проблемой, мы обнаружили, что добавление:
pool.join()
в код до pool.terminate()
, похоже, это останавливает, но, учитывая, что проблема находится в пространстве ядра, мы не уверены, что это что-то более существенное, чем «просто» небольшая задержка в коде, которая маскирует неявное состояние гонки.
Мы обнаружили, что sleep(0.05)
также, по-видимому, предотвращает это, предположительно по тем же причинам, поскольку пользовательское пространство вообще не может сделать недействительным кеширование записей каталога.
Не очень полезно, но это явно связано с вашим окружением. Ваш код работает до бесконечности без ошибок на macOS