Celery: Задачи не могут запускать подпроцессы

Созданный на 29 нояб. 2013  ·  68Комментарии  ·  Источник: celery/celery

Начиная с Celery 3.1.0 пул процессов ( celery.concurrency.prefork , бывший celery.concurrency.processes ) использует процессы-демоны для выполнения задач.

Процессам-демонам не разрешено создавать дочерние процессы, и в результате задачи, использующие пакет multiprocessing , не работают:

[2013-11-29 14:27:48,297: ERROR/MainProcess] Task app.add[e5d184c0-471f-4fc4-804c-f760178d4847] raised exception: AssertionError('daemonic processes are not allowed to have children',)
Traceback (most recent call last):
  File "/Users/aromanovich/Envs/celery3.1/lib/python2.7/site-packages/celery/app/trace.py", line 218, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/aromanovich/Envs/celery3.1/lib/python2.7/site-packages/celery/app/trace.py", line 398, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/aromanovich/Projects/celery/app.py", line 10, in add
    manager = multiprocessing.Manager()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/__init__.py", line 99, in Manager
    m.start()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 524, in start
    self._process.start()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 124, in start
    'daemonic processes are not allowed to have children'
Not a Bug

Самый полезный комментарий

@thedrow
Ты не понял. Дважды.
Нас беспокоит не то, что у вас нет ресурса (это вполне понятно и, к сожалению, очень распространенный случай в свободных программах). Мы обеспокоены тем, что билет закрыт из-за этого, это не то, как билеты работают.
Мы не «несчастны», мы шокированы.

Все 68 Комментарий

Это не изменилось между 3.0 и 3.1, поэтому я не уверен, почему вы получили эту ошибку сейчас, а не раньше.

Вот как можно воспроизвести эту ошибку.

app.py:

import multiprocessing
from celery import Celery

app = Celery(__name__, broker='amqp://192.168.33.40')
@app.task
def f():
    manager = multiprocessing.Manager()

sendtask.py:

import app

app.f.delay()

Я запускаю worker с помощью следующей команды: celery worker -A app.app -l debug .

С Celery 3.0.24 задача выполняется:

[2013-12-02 20:43:56,454: INFO/MainProcess] Task app.f[bcaab028-dbec-43a8-9259-ff7c35ff13d0] 
succeeded in 0.0169339179993s: None

В Celery 3.1.5 это не так:

[2013-12-02 20:48:38,946: ERROR/MainProcess] Task app.f[c9f1cdd3-ae38-493e-b7c7-b9636ed473d0] 
raised exception: AssertionError('daemonic processes are not allowed to have children',)

Я понимаю проблему следующим образом: celery.concurrency.prefork.TaskPool использует celery.concurrency.asynpool.AsynPool ; AsynPool наследуется от billiard.pool.Pool который запускает рабочие процессы демонов, а AsynPool не отменяет это поведение. Но вы правы, эта схема вроде не меняется между 3.0 и 3.1, так что я тоже запутался :)

И похоже, что я не одинок с этой проблемой: http://stackoverflow.com/questions/20149421/threads-in-celery-3-1-5

Одно отличие состоит в том, что рабочий процесс теперь является подклассом Process, где раньше он использовал аргумент функции: Process(target=) , возможно, есть разница в значениях по умолчанию для этих подходов.

многопроцессорность и старые версии биллиардных наборов daemon=True :
https://github.com/celery/billiard/blob/2.7/billiard/pool.py#L904

Так и в последней версии:
https://github.com/celery/billiard/blob/3.3/billiard/pool.py#L1039

Я считаю, что процесс задачи, являясь демоном, представляет собой серьезное ограничение для реализации задач.
Я написал задачу, которая использует многопроцессорность для ускорения операций, связанных с процессором. Все работает нормально, когда я запускаю воркер в терминале следующим образом:

рабочий сельдерея --app = tasks -Q wb -l info --concurrency = 1

Но когда я использую скрипт celeryd для запуска рабочего, я получаю следующее исключение:
AssertionError: демоническим процессам не разрешено иметь потомков

Я выяснил, что вызвало изменение в поведении.
Задачи запускаются с использованием процессов-демонов как в версии 3.0, так и в модуль celery / https://github.com/celery/billiard/commit/c676b94aa4144349b11ab31c82296a5d804909c9 multiprocessing не знал об этом, и поэтому позволял создавать подпроцессы.

Насколько я понимаю, была ошибка до версии 3.1 (задачам разрешалось создавать подпроцессы, что могло привести к потерянному состоянию), и теперь эта ошибка исправлена.

Решение не разрешать процессам демона python разветвляться кажется мне довольно произвольным. Признавая его добросовестность, я чувствую, что смогу полностью контролировать такое поведение, если захочу.

Привязка к одному процессу для каждой задачи кажется мне серьезным ограничением. Мысли?

Мне интересно, почему это ограничение существует вообще, предупреждение, которое я могу понять, но прямое запрещение его кажется глупым, когда вы можете полностью разветвлять процессы, используя другие средства.

@ask , можно ли инициализировать рабочий процесс сельдерея с флагом демона, равным False? Или сделать это настраиваемым?

@ilyastam кажется, мы комментировали одновременно

Я согласен с тем, что это кажется произвольным ограничением, но я хотел бы знать причину его добавления.

Это хорошо известная ошибка в posix-системах, но она все же разрешена. Вы можете очистить дочерние процессы в обработчике сигналов, но это не защитит вас от SIGKILL.

Я думаю, нам следует снять ограничение с биллиарда, даже если это будет отличаться от многопроцессорного поведения. Вы по-прежнему можете создавать дочерние процессы с помощью модуля subpocess или вызова fork низкого уровня, поэтому опытные пользователи должны иметь возможность создавать дочерние экземпляры billiard.Process .

@ilyastam Должна иметься возможность удалить оператор повышения, не нужно делать процессы "недемонами"

То есть процессам-демонам будет разрешено создавать дочерние процессы, даже если он не сможет их получить,
в любом случае, как работает posix.

Кстати, обратите внимание, что это не raise , это утверждение assert, которое будет удалено, если python запущен с PYTHONOPTIMIZE envvar или аргументом -O .

billiard 3.3.0.11 находится на PyPI, включая это изменение

@ask спасибо. Есть идеи, какая версия сельдерея получит это улучшение?

multiprocessing документация явно заявляет, что процессу-демону не разрешено создавать подпроцессы, и объясняет, почему. Что касается меня, это assert заявление выглядит более , как ему был поставлен здесь в качестве ярлыка для raise (люди часто делают это).

Это ограничение задокументировано, и я не думаю, что для Celery будет хорошей идеей тихо исправить multiprocessing и убрать его. Это могло привести к действительно неожиданным и пагубным последствиям.

Я могу вспомнить следующий пример (хотя он может показаться немного надуманным):

@app.task
def f():
    p = multiprocessing.Pool(3)
    p.map_async(time.sleep, [1000, 1000, 1000])

Будучи запущенным как обычная функция Python, этот код работает правильно. Но будучи запущенным как задача Celery (с использованием Celery версии 3.0. *), Он оставляет три подпроцесса, которые будут зависать навсегда; когда рабочий Celery завершает работу, эти подпроцессы становятся "осиротевшими".

Он не объясняет почему, он просто указывает поведение unix, которое вы ожидаете при запуске дочернего процесса. Несмотря на то, что это печально известное ограничение в unix, оно не мешает людям это делать. Это ничем не отличается от
запуск процесса subprocess.Popen или даже вызов fork() для запуска нового процесса. Так почему это должно быть незаконно?

Способ сделать ваш пример:

from billiard import Pool
from multiprocessing.util import Finalize

_finalizers = []

@app.task
def f():
    p = billiard.Pool(3)
    _finalizers.append(Finalize(p, p.terminate))
   try:
       p.map_async(time.sleep, [1000, 1000, 1000])
       p.close()
       p.join()
   finally:
       p.terminate()

Чтобы убить (-9) это, вам нужно также убить -9 дочерних процессов, но это то, что у вас будет
учитывать для всех процессов unix.

Не то чтобы я выступал за создание пула для каждой задачи, но я не понимаю, почему пользователи, которые знают, что они
делать, не должно быть разрешено запускать процессы из задачи.

Кроме того, мы ничего не исправляем, это изменение только в бильярде.

Кроме того, мы ничего не исправляем, это изменение только в бильярде.

Под "исправлением обезьяны" я подразумеваю это назначение, которое заменяет multiprocessing._current_process экземпляром billiard.process.Process : https://github.com/celery/billiard/blob/master/billiard/process.py # L53.

Я согласен с тем, что нет ничего плохого в запуске дочерних процессов, если они обрабатываются правильно (как в вашем примере). Я хочу сказать, что multiprocessing написано иначе, и мы не должны игнорировать ограничения его реализации.

@aromanovich По-

Он устанавливает _current_process так, чтобы переменная формата модулей журналирования processName работала, а объект биллиардного процесса имел тот же API, что и объект многопроцессорного процесса, поэтому можно безопасно установить текущий процесс.

И, кстати, вам придется использовать биллиард, чтобы ограничение было снято, использование многопроцессорности все равно вызовет исключение.

Также можно исправить эту проблему, используя такой подход:
http://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic
Это позволит пользователям продолжать использовать модуль многопроцессорности, избегая этой проблемы:
https://github.com/celery/billiard/issues/99

Я получаю эту ошибку при вызове задачи @parallel Fabric из задачи сельдерея.

@celery.task
def dostuff():
   execute(fabfile.push_settings, sid=site['sid'])

<strong i="7">@parallel</strong>
@roles(environment)
def push_settings(sid):
  #do stuff

@frodopwns использует ENV
экспорт PYTHONOPTIMIZE = 1
чтобы удалить это утверждение. вам нужно справиться со всем.

@xiaods Я думаю, что решил эту проблему примерно так:

@worker_process_init.connect
def configure_workers(sender=None, conf=None, **kwargs):
    Crypto.Random.atfork()

Проблема

У меня есть задача, которая вычисляет некоторые данные и загружает классификатор scikit-learn, чтобы делать прогнозы на основе этих данных. Когда я запускаю задачу сама по себе, все в порядке, но когда я запускаю ее с помощью Celery, я получаю сообщение об ошибке, когда задача пытается загрузить классификатор маринованного:

[2015-07-17 21:23:51,299: ERROR/MainProcess] Task app.f[329d0da4-2e0e-4e1f-8148-d64f47750b1f] raised unexpected: AttributeError("'Worker' object has no attribute '_config'",)
Traceback (most recent call last):
  File "/home/username/anaconda3/lib/python3.4/site-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/username/anaconda3/lib/python3.4/site-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/username/working/playground/celery/app.py", line 11, in f
    clf = pickle.load(open('clf.pickle', 'rb'))
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/ensemble/__init__.py", line 6, in <module>
    from .base import BaseEnsemble
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/ensemble/base.py", line 13, in <module>
    from ..externals.joblib import cpu_count
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/__init__.py", line 112, in <module>
    from .parallel import Parallel
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/parallel.py", line 23, in <module>
    from ._multiprocessing_helpers import mp
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/_multiprocessing_helpers.py", line 25, in <module>
    _sem = mp.Semaphore()
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/context.py", line 81, in Semaphore
    return Semaphore(value, ctx=self.get_context())
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 127, in __init__
    SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 59, in __init__
    kind, value, maxvalue, self._make_name(),
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 117, in _make_name
    return '%s-%s' % (process.current_process()._config['semprefix'],
AttributeError: 'Worker' object has no attribute '_config'

Воспроизвести

Создайте пустой классификатор и сохраните его как рассол:

import pickle
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier()
pickle.dump(clf, open('clf.pickle', 'wb'))

Создайте простое приложение ( app.py ):

import pickle
import sklearn
from celery import Celery

app = Celery(__name__, broker='amqp://localhost//')

@app.task
def f():
    print('hello')
    clf = pickle.load(open('clf.pickle', 'rb'))
    print(clf)

Запускаем сельдерей рабочий:

celery -A app worker --loglevel=debug

Запустите приложение:

python -c "from app import f; f.delay()"

Сообщение об ошибке:

...
AttributeError: 'Worker' object has no attribute '_config'

Решение

Я думаю, что должна быть возможность «обезьяны» Celery, чтобы позволить задачам запускать подпроцессы, особенно если такая «функция» существовала в прошлом. Прямо сейчас люди просто переходят на другие фреймворки, когда сталкиваются с этой проблемой: http://stackoverflow.com/questions/27904162/using-multiprocessing-pool-from-celery-task-raises-exception. Вот еще один пример этой ошибки: http://stackoverflow.com/questions/22674950/python-multiprocessing-job-to-celery-task-but-attributeerror.

Этот вопрос следует открыть повторно ...

Я столкнулся с той же проблемой. Я использую nltk внутри одного из моих воркеров, который, в свою очередь, импортирует scikit-learn что приводит к той же ошибке, которую показал

Кажется, я могу обойти это с помощью следующего кода:

from celery.signals import worker_process_init

@worker_process_init.connect
def fix_multiprocessing(**kwargs):
    from multiprocessing import current_process
    try:
        current_process()._config
    except AttributeError:
        current_process()._config = {'semprefix': '/mp'}

Очевидно, это очень грубый хакер, и я не знаю, что бы произошло, если бы я действительно использовал многопроцессорность (черт возьми, я даже не знаю, что такое semprefix ), но этого достаточно, чтобы получить scikit-learn работа снова.

Я оставляю это здесь для других людей, которые сталкиваются с той же проблемой, пока она не будет исправлена.

Может быть, это какая-то несовместимость с бильярдом на Python 3? Или он воспроизводится и на Python 2?

Сохраняется ли проблема, связанная с тем, что процессы сельдерея не могут создавать подпроцессы? Просматривая комментарии, можно сказать, что это было исправлено с помощью celery /

@martinth Спасибо, мне тоже

@xiaods Спасибо! Ваше решение работает для меня! Спасибо!

@gilinson это все еще проблема, и export PYTHONOPTIMIZE = 1 все еще "как бы исправляет" ее.
Просто столкнулся с той же проблемой, пытаясь запустить доступную книгу воспроизведения в задаче Celery.

@martinth Спасибо за взлом! У меня та же проблема:

  • Python 3.4.3
  • сельдерей == 3.1.18
  • scikit-learn == 0,17

Хак @martinth не работает для меня, я столкнулся с этим, пытаясь использовать многопроцессорность для ускорения некоторых вычислений. Вместо этого использовал модуль потоковой передачи, и, похоже, он избавил меня от этой ошибки, но при этом прервал обработку.

Использование многопроцессорной обработки на основе потоков.

from multiprocessing.dummy import Pool

Эта ошибка все еще возникает в python 2.7.5. Я не уверен, что он предназначен для решения этой проблемы, но из-за этого использование salt-ssh saltstack невозможно с сельдереем.

Закрытие, так как у нас нет ресурсов для выполнения этой задачи.

Возможное решение"

У меня была такая задача, что я пытался создать потоки, и это не удалось. Мне удалось заставить его работать: разветвляясь на сценарий bash, который сам разветвляется на интерпретатор python, который выполняет тот же точный код (и, следовательно, может создавать потоки, что было критично для моего варианта использования).

Я не понимаю, почему билет закрыт. Если у вас нет ресурсов для этого, вы можете прокомментировать это, но это не закрывает заявку. Вы просто скрываете ошибку, делая это.

Что особенно плохо для заявки, помеченной как «критическая» как по приоритету, так и по серьезности.

@orzel +1.
Приоритет: критический
Степень серьезности: критическая
Закрытие, так как у нас нет ресурсов для выполнения этой задачи.

Это шутка. Если у вас сейчас нет ресурсов - не чините сейчас. Исправьте это, когда у вас будут ресурсы. Закрытие тикета не устранит проблему

@orzel @Templarrr Я пометил этот билет как критический, поэтому @ask здесь не виноват.
Вы можете быть недовольны этим, но протест не поможет.
Нам нужно обрабатывать наш бэклог в зависимости от того, что можно предпринять, а что нет, а что в настоящее время нет.
Это сложно сделать, но кто-то должен это сделать.
Если эта проблема мешает вам, попробуйте ее исправить. Обещаю, что если исправление правильное и есть соответствующие тесты, я объединю его.

@thedrow
Ты не понял. Дважды.
Нас беспокоит не то, что у вас нет ресурса (это вполне понятно и, к сожалению, очень распространенный случай в свободных программах). Мы обеспокоены тем, что билет закрыт из-за этого, это не то, как билеты работают.
Мы не «несчастны», мы шокированы.

Я также полностью не согласен с тем, чтобы закрыть это.

Я думаю, мы все можем согласиться с тем, что это действительно ошибка. И хотя действительно печально, что недостаточно ресурсов, закрытие ошибки _definite_ не поможет. Вы не можете знать, может быть, завтра кто-то придет долго и думает: «Давайте исправим некоторые ошибки в Celery», просто чтобы просмотреть открытые проблемы, и думает: «Ну, здесь нет никакой интересной работы ... давайте работать вместо _OtherProject_ ".
Кроме того, закрытие этой проблемы затруднит ее поиск. Я не знаю, как вы используете Github, но когда я обнаруживаю потенциальную проблему, я сначала ищу в системе отслеживания проблем открытую проблему. Обычно есть много дискуссий, и, более того, никогда не существует обходного пути (как в этом случае), который я могу использовать сейчас. Только если я действительно впадаю в отчаяние, я начинаю просматривать закрытые вопросы.

Это не «обработка невыполненных работ», это корректировка числа. Если я смотрю на то, что можно использовать, я _do_ смотрю на количество открытых проблем, но я также всегда смотрю на количество звезд (которое довольно велико для сельдерея). Я понимаю, что желательно иметь небольшое количество ошибок как для публичной апелляции, так и для вас самих. Честно говоря, я понимаю, что видеть «250 открытых вопросов» - не очень хорошее число и звучит ошеломляюще.

Если у вас нет людей для работы над этим в следующем месяце (или даже году), это нормально. Только не закрывайся. Закрытие должно происходить только в том случае, если проблема либо решена, либо _абсолютно ясно_, что это _ никогда_ не будет выполнено. И то и другое здесь не так.

Просто удалите «Критические» флаги и добавьте флаг «Отложено» для всего, что не может быть обработано сейчас, но должно быть обработано, если ресурс _are_ доступен.

Я не уверен, что мы действительно сможем решить эту проблему. Мы не можем изменить принцип работы unix, но можем ли мы отправить патч вверх по течению, чтобы снять ограничение?

Возможно, в Linux есть решения для конкретных платформ, но это необходимо изучить. Он был открыт уже 2 года, и ни у кого не было стимула его исправить, поэтому вряд ли это будет исправлено в ближайшей функции.

Я закрыл более 200 проблем и пометил более 30 тысяч писем как прочитанные, поэтому некоторые из них обязательно будут спорными, и нам, возможно, придется открыть их повторно. Я полностью на это рассчитываю, но было бы неплохо, если бы мы также могли внести свой вклад в решение, например, помогая задокументировать дефект, если это единственный известный вариант.

Мы завалены работой, пытаясь реализовать огромный проект без каких-либо ресурсов. Мы не можем отсортировать проблемы или узнать, какие проблемы уже были исправлены.

Ну ладно. Но можно ли хотя бы задокументировать тот факт, что «Вы не можете использовать многопроцессорность, если пишете код для сельдерея»? Я имею в виду ... всегда найдутся люди, которые не читают это, но, по крайней мере, вы можете указать на это и сказать: «Видите, это задокументировано. Мы не можем это изменить. Разбирайтесь с этим».

Мой список дел огромен, вы можете редактировать документацию прямо на github, так что вносить такие изменения очень легко :(

Я делаю это не для того, чтобы скрыть проблемы, я делаю это, чтобы побудить людей к действию именно потому, что я хочу, чтобы это улучшилось.

@ask Можем ли мы применить многопроцессорность внутри задачи с использованием сельдерея в django?
Есть ли альтернатива этому?

@abhisheksachan, вы должны прочитать весь этот выпуск, прежде чем размещать такой вопрос

@abhisheksachan Я не пробовал этого пару лет, но я заставил его работать, используя https://pypi.python.org/pypi/billiard, потому что он позволяет демонизировать подпроцессы.

Да, вы должны заменить импорт из multiprocessing на billiard, например:

from multiprocessing import Process

->

from billiard import Process

У нас нет возможности отключить ограничение на многопроцессорность, но мы утверждаем, что в любом случае ограничений быть не должно, поэтому наша многопроцессорная вилка позволяет это.

Для всех, кто, как и я, инвестировал в разработку системы очередей, _ПЕРЕД_ обнаружением этого ограничения и нуждающимся в другом обходном пути, пока они не смогут перейти на более удобную оболочку python rabbitMQ, мне удалось обойти проблему, вызвав внешний подпроцесс, который может сам вилка чисто. Этот разветвленный процесс теперь находится за пределами песочницы сельдерея, и все работает так, как должно.

В примере OP замените:

app = Celery(__name__, broker='amqp://192.168.33.40') 
@app.task
def f():
    manager = multiprocessing.Manager()

с участием:

app = Celery(__name__, broker='amqp://192.168.33.40')
@app.task
def f():
    process = subprocess.Popen(["program"]) # or the newer post 3.5 run version
    process.wait()
    # analyze exit code

и "программа" будет выглядеть (на платформе POSIX unix / linux)

import os

def main():
      manager = multiprocessing.Manager()

# this is equivalent to "(cmd )&" under bash
pid = os.fork()
if pid == 0:
    cpid = os.fork()
    if cpid == 0:
        main()
    else:
        exit(0)
else:
    os.wait(pid)

Имейте в виду, что управление процессором выходит за рамки сельдерея, что как бы противоречит идее использования сельдерея, но, учитывая, что вы собирались использовать многопроцессорность, вы, вероятно, в любом случае захотите обрабатывать использование процессора вне сельдерея.

По крайней мере, это ограничение должно быть задокументировано. Я просмотрел документ и не нашел.

Опять же, не стесняйтесь отправлять запрос на перенос с изменениями документации.

вслед за комментарием @martinth , на Python 3.5.2, Celery 4.0.0 и billiard 3.5.0 его решение не сработало, поскольку многопроцессорность проверяет демонизируемый процесс и останавливает его от запуска дочернего процесса.

Мне удалось снять ограничение, сбросив флаг демона рабочего. Я почти уверен, что это плохая идея, но она позволяет запускать multiprocessing.Pools из задачи сельдерея.

@worker_process_init.connect
def fix_multiprocessing(**kwargs):
    # don't be a daemon, so we can create new subprocesses
    from multiprocessing import current_process
    current_process().daemon = False

Тем не менее, IMHO Celery должен добавить документированную опцию, чтобы настроить, запускает ли он рабочих как демонов. Обратите внимание: я использую сельдерей в стручке k8, поэтому сельдерей запускается как процесс переднего плана с использованием celery worker , и мне действительно не нужны демонизированные рабочие.

@miraculixx Проблема с этим предложением в том, что у нас будет больше режимов сбоя, которые нужно обработать, и больше проблем, которые нужно решить. Мы бы предпочли этого избежать.

Хотя использование многопроцессорной обработки не удается в сочетании с пулом предварительных вилок, похоже, что при использовании соло-пула это работает. Поэтому я предполагаю, что обходным путем было бы создать несколько рабочих сельдерея с одиночным пулом вместо одного с несколькими дочерними элементами в предварительном пуле. Это звучит законно? Конечно, в этом случае некоторые параметры, такие как max-mem-per-child, работать не будут.

Я думаю, что это в основном проблема дизайна приложения. Это особая проблема, с которой сталкивается daemonic processes are not allowed to have children , потому что вы знаете, вы достигли точки, когда вам нужно перепроектировать все приложение. Но это ограничение уровня ОС, без серьезных побочных эффектов его не обойти. Демонические процессы также не могут иметь потомков в C. Это не относится к Python. Раньше велись споры о производительности потоков и процессов, и в результате выяснилось, что ни один из них не является значительно лучше или хуже другого.

Предлагаю два варианта (и говорю вообще, а не о сельдерее здесь)

  • Используйте subprocess.Popen для создания независимого процесса, который может иметь потомков и использовать сокеты UNIX для межпроцессного взаимодействия.
  • Действительно ли необходимо, чтобы потоки создавались разветвленным процессом, а не вашим основным процессом?

Что бы это ни стоило, моим вариантом использования тогда было то, что я хотел запустить длительный подпроцесс, который часто быстро вылетал из-за нетривиальных (и не связанных с безопасностью) проблем с вводом. Так что идея заключалась в том, чтобы, по крайней мере, убедиться, что процесс запущен успешно.

В долгосрочной перспективе он оказался неудачным по разным причинам, поэтому новая архитектура естественным образом вернулась к «естественному» использованию асинхронных рабочих процессов сельдерея. Так что я согласен с мыслью о том, действительно ли необходимо разветвление; задача - вилка.

что бы это ни стоило, моим вариантом использования был запуск процессов scikit-learn, которые используют многопроцессорность (через joblib). С тех пор я разработал бэкэнд сельдерея для joblib, что означает, что scikit-learn запускает параллельные процессы с использованием сельдерея, и мой вышеупомянутый хак больше не требуется. Это на стадии POC, пока не готово для прайм-тайма.

@miraculixx Это где-то размещалось? Я бы хотел посмотреть и / или попробовать. Я сталкиваюсь с той же проблемой, что и вы - подпроцессы порождения sklearn - и я в основном отказался от сельдерея.

@pgeez Если вы не заботитесь об использовании подпроцессов в sklearn, вы можете установить переменную среды JOBLIB_MULTIPROCESSING = 0. См. Https://github.com/scikit-learn/scikit-learn/blob/0.18.X/sklearn/externals/joblib/_multiprocessing_helpers.py

@jennaliu спасибо за мысль, но, как и @miraculixx , мне нужно включить многопроцессорность.

Вы, ребята, пробовали старый трюк с

Вы прочитали заголовок этой ветки?!?!?

@sebastroy, очевидно, я двойную вилку, но теперь вижу, что мое замешательство было связано с тем, что вилки демона были убиты сельдереем, а не тем, что их полностью предотвращали.

Попался. Да, в моей предыдущей жизни я использовал C, так что это было похоже на хлеб с маслом.

Обходной путь, который я использую, - это subprocess.Popen, который отлично работает, но тогда вам нужно переопределить некоторую логику (и создать версию программы для оболочки), которую сельдерей должен делать в первую очередь. Но я исправил это, изменив поведение реализации API верхнего уровня. Я думаю, это больше соответствует назначению сельдерея. Упростите некоторую логику тоже, что на низком уровне.

К счастью, я обнаружил эту проблему, когда пытаюсь запустить доступную playbook в задаче Celery.
Метод, предоставленный @martinth , у меня не сработал. Я печатаю current_process()._config и получаю
{'authkey': b"y&e\x8d'\xcb\xd4\r\xd2\x86\x06\xe7\x9e\x14\xaf \xbc\xc4\x95\xa5G\xec&[i\x19\xf3G-\x06\xac\x19", 'semprefix': '/mp', 'daemon': True} .
Затем я переназначаю поле daemon на False , и оно работает.

Есть ли какие-то решения или другие реализации, позволяющие запускать многопроцессорную задачу в задаче?

@HeartUnchange : в последнее время мы усердно работаем над проектом больших данных, в котором мы хотим использовать сельдерей в качестве распределенного компонента. и с вашим гидом нам очень повезло решить эту проблему. см. конфигурацию задачи:

     @app.task
    def handleBigZipfile(filename,nid):
    current_process()._config['daemon'] = False
    logger.info('{} begin handle!'.format(filename))
    handleAll(filename,nid)
     logger.info('{} is done!'.format(filename))

Решение в порядке! мы начинаем проект в 2017.1, и теперь прототип готов! прошло девять месяцев! Я благодарен вам! и моя благодарность невыразима!
Не могли бы вы рассказать подробнее о том, как вы решаете проблему! мы очень хотим это знать!

Привет ,

У меня довольно стандартная настройка: Django + Rabbitmq + celery-4.0.2 + python-2.7 + centOS-7

Я пытаюсь создать процесс, используя стандартный модуль многопроцессорности python в сельдерее.

Процессам-демонам не разрешено создавать дочерние процессы, и, как следствие, задачи, использующие пакет многопроцессорности, не работают:
Используемая для запуска команда: celery worker -B -A celery_task -l debug
Журналы отслеживания:

[2017-09-26 23:27:08,838: WARNING/PoolWorker-2] ERROR
[2017-09-26 23:27:08,839: WARNING/PoolWorker-2] Traceback (most recent call last):
[2017-09-26 23:27:08,839: WARNING/PoolWorker-2] File "/home/induser/config.py", line 612, in main
[2017-09-26 23:27:08,840: WARNING/PoolWorker-2] mylog_process = mp.Process(target=test_logger_process, args=(myqueue,))
[2017-09-26 23:27:08,840: WARNING/PoolWorker-2] File "/usr/lib64/python2.7/multiprocessing/process.py", line 98, in __init__
[2017-09-26 23:27:08,841: WARNING/PoolWorker-2] self._authkey = _current_process._authkey
[2017-09-26 23:27:08,841: WARNING/PoolWorker-2] AttributeError: 'Process' object has no attribute '_authkey'

В чем может быть причина, по которой процесс не запускается?
Вот код:

import multiprocessing as mp
from celery.schedules import crontab
from celery.decorators import periodic_task

@periodic_task(run_every=crontab(minute='*/1'), name='test_process_celery')
def main():
data = config_read()
try:
    myqueue = mp.Queue(-1)
    mylog_process = mp.Process(target=test_logger_process, args=(myqueue,))
    mylog_process.start()
    . . .
    . . .
except Exception as e:
    raise
finally:
    mylog_process.join()

Спасибо.

попробуйте мастер и сообщите, если это все еще проблема

Ошибка все еще есть. Я попытался использовать подпроцесс с:

from multiprocessing import Process, Value
import ctypes

[...]
        result = Value('i', 0)
        text = Value(ctypes.c_char_p, fail_string.encode())
        p = Process(target=reader.find_text_async, args=(result, text, ))
        p.start()
        p.join(5)

        if p.is_alive():
            logging.WARNING("Manual terminating the process 'find_text_async'")
            p.terminate()

но с ветвью мастера сельдерея он говорит:

Файл "/usr/lib/python3.5/multiprocessing/process.py", строка 103, в начале
'демоническим процессам не разрешено иметь детей'
AssertionError: демоническим процессам не разрешено иметь потомков

РЕДАКТИРОВАТЬ

Я заменил многопроцессорность на бильярд, и он работает!

from billiard import Process, Value

Была ли эта страница полезной?
0 / 5 - 0 рейтинги