Я наблюдаю странное поведение многопроцессорного модуля. Кто-нибудь может объяснить, что здесь происходит?
Следующие MWE зависает (работает вечно и без ошибок):
#!/usr/bin/env python3
import multiprocessing
import numpy as np
from skimage import io
from sklearn.cluster import KMeans
def create_model():
sampled_pixels = np.random.randint(0, 255, (800,3))
kmeans_model = KMeans(n_clusters=8, random_state=0).fit(sampled_pixels)
def process_image(test, test2):
image = np.random.randint(0, 255, (800,3))
kmeans_model = KMeans(n_clusters=8, random_state=0).fit(image)
image = kmeans_model.predict(image)
def main():
create_model()
with multiprocessing.Pool(1) as pool:
pool.apply_async(process_image, args=('test', 'test'))
pool.close()
pool.join()
if __name__ == "__main__":
main()
Однако, если я либо удалю строку create_model()
ИЛИ изменю
def process_image(test, test2)
# as well as
pool.apply_async(process_image, args=('test', 'test'))
к
def process_image(test)`
# and
pool.apply_async(process_image, args=('test'))
код выполняется успешно, как и должно быть, поскольку аргументы, а также вызов функции create_model()
полностью избыточны.
Приложение
> pip list
Package Version
------------- ---------
imageio 2.34.0
joblib 1.4.0
lazy_loader 0.4
networkx 3.3
numpy 1.26.4
packaging 24.0
pillow 10.3.0
pip 23.2.1
scikit-image 0.23.1
scikit-learn 1.4.2
scipy 1.13.0
threadpoolctl 3.4.0
tifffile 2024.2.12
> python --version
Python 3.12.2
Думаю, я отследил это ошибку/недостаток в GNU OpenMP. Короче говоря, GNU OpenMP, используемый scikit-learn, не является безопасным для форков:
Если ваша программа намерена стать фоновым процессом [...], вы не должны использовать функции OpenMP до ее разветвления. После использования функций OpenMP ветвление разрешено только в том случае, если дочерний процесс не использует функции OpenMP или делает это как совершенно новый процесс (например, после exec()).
Минимальный способ вызвать это:
import multiprocessing
from sklearn.cluster import KMeans
def kmeans():
KMeans(n_clusters=2, random_state=0).fit([[1, 1], [2, 2]])
kmeans()
with multiprocessing.Pool(1) as pool:
pool.apply_async(kmeans)
pool.close()
pool.join()
О возможных способах смягчения последствий см. по этой ссылке.
args=('test'))
.... это опечатка, в кортежах одного элемента нужна запятая, иначе скобки игнорируютсяargs=('test',))
... возможно, это не связано