4
votes

uWSGI et joblib Semaphore: Joblib fonctionnera en mode série

J'exécute joblib dans une application Flask vivant dans un conteneur Docker avec uWSGI (démarré avec les threads activés) qui est démarré par supervisord.

Le démarrage du serveur Web affiche l'erreur suivante:

XXX

Une idée de comment résoudre ce problème et faire fonctionner joblib en parallèle? Merci!


Les packages suivants sont installés dans le conteneur du docker:

exception calling callback for <Future at 0x7fbc520c7eb8 state=finished raised TerminatedWorkerError>
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/joblib/externals/loky/_base.py", line 625, in _invoke_callbacks
    callback(self)
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 309, in __call__
    self.parallel.dispatch_next()
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 731, in dispatch_next
    if not self.dispatch_one_batch(self._original_iterator):
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 759, in dispatch_one_batch
    self._dispatch(tasks)
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 716, in _dispatch
    job = self._backend.apply_async(batch, callback=cb)
  File "/usr/local/lib/python3.7/site-packages/joblib/_parallel_backends.py", line 510, in apply_async
    future = self._workers.submit(SafeFunction(func))
  File "/usr/local/lib/python3.7/site-packages/joblib/externals/loky/reusable_executor.py", line 151, in submit
    fn, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/joblib/externals/loky/process_executor.py", line 1022, in submit
    raise self._flags.broken
joblib.externals.loky.process_executor.TerminatedWorkerError: A worker process managed by the executor was unexpectedly terminated. This could be caused by a segmentation fault while calling the function or by an excessive memory usage causing the Operating System to kill the worker. The exit codes of the workers are {EXIT(1), EXIT(1), EXIT(1), EXIT(1)}


EDIT

Les problèmes sont soit dus à uWSGI, nginx ou supervisord. Les droits manquants sur dev / shm ne sont pas le problème car les sémaphores peuvent être créés si j'exécute directement le serveur flask. Retrouvez ci-dessous les fichiers de configuration des trois services. Clause de non-responsabilité, je suis le serveur Web noob, et les configurations sont nées en copiant et collant à partir de différents blogs juste pour le faire fonctionner :-D

Voici donc ma configuration uwsgi:

unable to load configuration from from multiprocessing.semaphore_tracker import main;main(14)


4 commentaires

pouvez-vous fournir une un exemple minimal reproductible ?


C'est une bonne idée, nous en fournirons un plus tard aujourd'hui ou demain.


J'ai ajouté un exemple hébergé sur github. C'est un peu trop gros pour être affiché ici sous forme de texte.


Il s'agit d'un bogue causé par le fait que le binaire uwsgi embarque l'interpréteur Python et sys.executable pointe le binaire uwsgi au lieu du binaire python habituel. Loky pourrait être corrigé pour détecter cette situation et essayer de rechercher la ligne de commande python au lieu d'utiliser naïvement sys.executable: github.com/tomMoral/loky/issues/207 N'hésitez pas à soumettre un PR :) Un correctif similaire pourrait être apporté au module concurrent.futures dans la bibliothèque standard de Python.


3 Réponses :


0
votes

Il semble que la sémaphoration n'est pas activée sur votre image: Joblib vérifie multiprocessing.Semaphore () et seul root a l'autorisation de lecture / écriture sur la mémoire partagée dans / dev / shm . Jetez un œil à cette question et à cette réponse .

Ceci est exécuté dans l'un de mes conteneurs.

none /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0

Si vous exécutez en tant que non-root, vous devez modifier l'autorisation sur / dev / shm . Pour définir les autorisations correctes, vous devez modifier le / etc / fstab dans votre image Docker:

$ ls -ld /dev/shm
drwxrwxrwt 2 root root 40 Feb 19 15:23 /dev/shm


5 commentaires

Une idée comment? Si RUN echo "none / dev / shm tmpfs rw, nosuid, nodev, noexec 0 0"> / etc / fstab et RUN ls -ld / dev / shm I toujours obtenir drwxrwxrwt 2 root root 40 février 21 09:21 / dev / shm


Pourriez-vous essayer de compiler et d'exécuter ce programme dans votre conteneur? Compilez avec gcc -lrt -pthread main.c . Je veux savoir s'il s'agit d'un problème système ou spécifique à certaines bibliothèques.


C'est étrange. Si vous obtenez l'autorisation drwxrwxrwt sur / dev / shm / , vous devriez pouvoir y accéder même en tant que non-root.


Compiler et exécuter votre programme dans le conteneur docker donne Exemple de données écrites Valeur de mySem = 1


C'est certainement dû à uWSGI, nginx ou supverisord. Si j'exécute le serveur flask en mode débogage dans le conteneur et joblib fonctionne parfaitement. J'ajouterai les configurations à mon article principal.



2
votes

Eh bien, j'ai trouvé une réponse à mon problème. Cela résout le problème en termes de capacité à exécuter une bibliothèque dépendante de joblib avec superviseur et nginx dans le docker. Cependant, ce n'est pas très satisfaisant. Je n'accepterai donc pas ma propre réponse, mais je la poste ici au cas où d'autres personnes auraient le même problème et auraient besoin de trouver une solution correcte .

La solution consiste à remplacer uWSGI par gunicorn . Au moins, je sais maintenant à qui est la faute. J'apprécierais toujours une réponse qui résout le problème en utilisant uWSGI instaed de gunicorn.


3 commentaires

Pouvez-vous vérifier si joblib a besoin de threads synchrones pour fonctionner? uWSGI crée des ouvriers sur des threads asynchrones, ce qui créera des problèmes avec les applications nécessitant une nature synchrone. J'ai rencontré le même problème lors du déploiement de mes modèles tensorflow. Gunicorn prend en charge les travailleurs de synchronisation par défaut, tout comme la solution naturelle.


Comment puis-je vérifier ou vérifier si joblib a besoin de threads synchrones?


La bonne solution serait de changer loky pour implémenter: github.com/tomMoral/loky / issues / 207 # issuecomment-485137208



9
votes

C'était tout un terrier de lapin.

La page des problèmes de joblib sur Github contient des messages similaires sur l'échec de joblib avec Uwsgi. Mais la plupart sont pour l'ancien backend multiprocessing . Le nouveau backend loky était censé résoudre ces problèmes.

Il y avait PR pour le backend multitraitement qui a résolu ce problème pour uwsgi:

joblib.Parallel(n_jobs=4,prefer="threads")(joblib.delayed(sqrt)(i ** 2) for i in range(10))

Mais il a échoué parfois de manière aléatoire et est retombé au même problème que le PR ci-dessus a tenté de résoudre.

Des recherches plus poussées ont révélé que le backend actuel loky parallélise les processus par défaut ( docs ). Mais ces processus n'ont pas d'accès à la mémoire partagée et ont donc besoin de canaux sérialisés et mis en file d'attente. C'est probablement la raison pour laquelle uWSGI échoue et que gunicorn fonctionne.

J'ai donc essayé de passer aux threads au lieu des processus:

joblib.Parallel(n_jobs=4,backend="multiprocessing")(joblib.delayed(sqrt)(i ** 2) for i in range(10))

Et ça marche :)


2 commentaires

Merci beaucoup, j'ai aidé à trouver une solution de contournement pour un problème très similaire. Existe-t-il un moyen de convaincre joblib utilisé dans une dépendance d'utiliser prefer = "threads" ?


C'est plus d'un an après votre réponse, mais le problème existe toujours dans joblib. J'ai aussi le même problème des échecs aléatoires. Pour l'instant, j'ai essayé d'utiliser le backend multiprocesseur, et cela semble fonctionner. Comment l'utilisation des threads aide / fonctionne-t-elle? D'autant plus que Python n'est pas intrinsèquement multithread, mais mieux adapté au multitraitement?