Celery: لا يُسمح للمهام ببدء العمليات الفرعية

تم إنشاؤها على ٢٩ نوفمبر ٢٠١٣  ·  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()

أقوم بتشغيل العامل باستخدام الأمر التالي: celery worker -A app.app -l debug .

مع نجاح مهمة الكرفس 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

مع الكرفس 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(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

أعتقد أن عملية المهمة كونها خفية تمثل قيدًا خطيرًا على تنفيذ المهام.
لقد كتبت مهمة تستخدم المعالجة المتعددة لتسريع العمليات المرتبطة بوحدة المعالجة المركزية. كل شيء يعمل بشكل جيد عندما أقوم بتشغيل عامل في محطة على النحو التالي:

عامل الكرفس - التطبيق = المهام - Q wb -l info --concurrency = 1

لكن عندما أستخدم برنامج celeryd النصي لبدء عامل ، أحصل على هذا الاستثناء:
AssertionError: العمليات الشيطانية غير مسموح لها بإنجاب الأطفال

اكتشفت سبب التغيير في السلوك.
يتم تشغيل المهام باستخدام العمليات الخفية في كل من 3.0 و 3.1 ، ولكن حتى الكرفس / البلياردو @ 4c32d2e و https://github.com/celery/billiard/commit/c676b94aa4144349b11ab31c82296a5d804909c9 multiprocessing لم تكن الوحدة النمطية على علم بذلك وبالتالي كان يسمح بإنشاء عمليات فرعية.

حسب فهمي ، كان هناك خطأ قبل الإصدار 3.1 (تم السماح للمهام بإنشاء عمليات فرعية ، مما قد يؤدي إلى حالة اليتيمة) والآن تم إصلاح هذا الخطأ.

يبدو لي أن قرار عدم السماح لعمليات خفيّة البايثون بالتشعب هو أمر تعسفي إلى حد ما. بينما أدرك حسن النية في ذلك ، أشعر أنني يجب أن أكون قادرًا على التحكم الكامل في هذا السلوك إذا اخترت ذلك.

يبدو أن الالتزام بعملية واحدة لكل مهمة يمثل قيدًا خطيرًا بالنسبة لي. أفكار؟

أتساءل لماذا يوجد هذا القيد في المقام الأول ، تحذير يمكنني فهمه ولكن الرفض الصريح له يبدو سخيفًا عندما تكون قادرًا تمامًا على تفرع العمليات باستخدام وسائل أخرى.

ask ، هل سيكون ذلك ممكنًا لتهيئة عملية عامل الكرفس مع كون العلم الخفي False؟ أو جعل هذا شكلي؟

ilyastam يبدو أننا كنا نعلق في نفس الوقت

أوافق على أنه يبدو قيدًا تعسفيًا ، لكنني أتمنى لو كنت أعرف الأساس المنطقي وراء إضافته في المقام الأول.

هذا مأزق معروف في أنظمة البوزيكس ، لكنه لا يزال مسموحًا به. يمكنك تنظيف العمليات الفرعية في معالج الإشارة ، على الرغم من أن ذلك لا يحميك من SIGKILL.

أعتقد أنه يجب علينا إزالة القيد من لعبة البلياردو ، على الرغم من أن ذلك قد يختلف عن سلوك المعالجة المتعددة. لا يزال بإمكانك إنشاء عمليات فرعية باستخدام الوحدة النمطية subpocess أو باستخدام المستوى المنخفض fork call ، لذلك يجب أن يتمكن المستخدمون المتمرسون من إنشاء مثيل billiard.Process التابع.

ilyastam يجب أن يكون قادرًا على إزالة بيان الزيادة ، ولا تضطر إلى جعل العمليات "غير خفية"

أي أنه سيسمح للعمليات الخفية بإنشاء عمليات فرعية حتى لو لم تكن قادرة على جنيها ،
وهي طريقة عمل posix على أي حال.

راجع للشغل ، لاحظ أن هذا ليس raise ، إنه عبارة تأكيد ، والتي ستتم إزالتها إذا بدأ Python بـ envvar PYTHONOPTIMIZE أو الوسيطة -O .

البلياردو 3.3.0.11 موجودة على PyPI بما في ذلك هذا التغيير

@ اسأل شكرا لك. أي فكرة عن أي إصدار من الكرفس سيشهد هذا التحسن؟

تنص وثائق multiprocessing صراحة على أن العملية الخفية غير مسموح بها لإنشاء عمليات فرعية وتشرح السبب. بالنسبة لي ، فإن عبارة assert تبدو أشبه بوضعها هنا كاختصار لـ raise (الناس يفعلون ذلك غالبًا).

تم توثيق هذا القيد ولا أعتقد أنه من الجيد أن يقوم الكرفس بصمت بترميم القرد multiprocessing وإزالته. يمكن أن يؤدي إلى عواقب غير متوقعة وضارة حقًا.

يمكنني التفكير في المثال التالي (قد يبدو مفتعلًا بعض الشيء):

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

يجري تشغيله كوظيفة عادية في Python ، يعمل هذا الرمز بشكل صحيح. ولكن يجري تشغيلها كمهمة كرفس (باستخدام الإصدار 3.0 من Celery. *) ، فإنها تترك ثلاث عمليات فرعية ستتوقف إلى الأبد ؛ عندما يستقيل عامل الكرفس ، ستصبح هذه العمليات الفرعية يتيمة.

إنه لا يفسر السبب ، إنه ينص فقط على سلوك يونكس الذي تتوقعه عند بدء عملية طفل - طفل. على الرغم من أنه قيد سيئ السمعة في نظام التشغيل 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 عمليات الطفل ، لكن هذا شيء سيكون لديك
للنظر في جميع عمليات يونكس.

لا يعني ذلك أني أدعو إلى إنشاء تجمع لكل مهمة ، لكنني لا أرى لماذا المستخدمين ، الذين يعرفون ما هم
القيام به ، لا ينبغي السماح له بالبدء في العمليات من المهمة.

أيضا ، نحن لا نرقع القرد أي شيء هذا تغيير في لعبة البلياردو فقط.

أيضا ، نحن لا نرقع القرد أي شيء هذا تغيير في لعبة البلياردو فقط.

أعني بـ "monkey patching" هذا الواجب ، الذي يستبدل multiprocessing._current_process بمثيل billiard.process.Process : https://github.com/celery/billiard/blob/master/billiard/process.py # L53.

أوافق على أنه لا حرج في بدء عمليات الطفل والطفل إذا تم التعامل معها بشكل صحيح (كما في المثال الخاص بك). وجهة نظري هي أن multiprocessing لم يُكتب بهذه الطريقة ويجب ألا نتجاهل قيود التنفيذ.

aromanovich لا يمكن كتابتها بأي طريقة أخرى ، فهي ليست قيودًا على المعالجة المتعددة ، إنها قيود على نظام Unix.

يقوم بتعيين _current_process بحيث يعمل متغير تنسيق وحدات التسجيل النمطية processName ، ويكون لكائن عملية البلياردو نفس واجهة برمجة التطبيقات مثل كائن عملية المعالجة المتعددة ، لذا من الآمن تعيين العملية الحالية.

وبالمناسبة ، سيتعين عليك استخدام البلياردو لرفع القيد ، وسيظل استخدام المعالجة المتعددة يثير الاستثناء.

يمكن أيضًا إصلاح هذه المشكلة باستخدام هذا الأسلوب:
http://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic
مما يسمح للمستخدمين بالاستمرار في استخدام وحدة المعالجة المتعددة ، وتجنب هذه المشكلة:
https://github.com/celery/billiard/issues/99

تلقيت هذا الخطأ عند استدعاء مهمة نسيج متوازية من داخل مهمة كرفس.

@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 لعمل تنبؤات بناءً على تلك البيانات. عندما أقوم بتشغيل المهمة بمفردها ، يكون كل شيء على ما يرام ، ولكن عندما أقوم بتشغيلها باستخدام الكرفس ، أحصل على خطأ عندما تحاول المهمة تحميل المصنف المخلل:

[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'

حل

أعتقد أنه يجب أن يكون هناك خيار لـ "monkeypatch" الكرفس للسماح للمهام ببدء العمليات الفرعية ، خاصةً إذا كانت هذه "الميزة" موجودة في الماضي. في الوقت الحالي ، ينتقل الأشخاص ببساطة إلى أطر عمل أخرى عندما يواجهون هذه المشكلة: 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 مما يؤدي إلى نفس الخطأ الذي أظهرهostrokach .

يبدو أنني قادر على حل هذه المشكلة باستخدام الكود التالي:

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 أيضًا؟

هل المشكلة الأصلية المتمثلة في عدم قدرة عمليات الكرفس على إنشاء عمليات فرعية لا تزال مشكلة؟ إذا نظرنا إلى الوراء في التعليقات ، فقد تم إصلاحه باستخدام الكرفس / البلياردو @ e6bb0f7 للإصدار 3.3. ومع ذلك ، فإن الالتزام اللاحق (celery / billiard @ c7eedbd0ee1498e76d4fa1affac5b1a275660ee7) أعاد تقديم عبارة تأكيد مشابهة جدًا في طريقة البدء لـ 3.4. لا توجد مشكلة بالنسبة لي لأنني في الإصدار 3.3 ، ولكن أردت فقط أن أشير إلى ما إذا كان يمكن أن يخلق مشاكل في المستقبل.

martinth شكرًا ، هذا الاختراق يعمل معي أيضًا!

xiaods شكرا لك! الحل الخاص بك يعمل بالنسبة لي! شكرا!

gilinson لا تزال مشكلة وتقوم بتصدير PYTHONOPTIMIZE = 1 لا يزال "kinda fixes".
واجهت للتو نفس المشكلة ، في محاولة لتشغيل كتاب قواعد اللعبة في مهمة الكرفس

martinth شكرا

  • Python 3.4.3
  • الكرفس == 3.1.18
  • scikit-learn == 0.17

لم ينجح اختراق

باستخدام المعالجة المتعددة القائمة على الخيط ، عملت الدمية في الكرفس بالنسبة لي:

from multiprocessing.dummy import Pool

لا يزال هذا الخطأ يحدث في Python 2.7.5 أيضًا. لست متأكدًا مما إذا كان المقصود منه معالجته على الإطلاق ، لكن هذا يجعل استخدام ملح الكرفس غير صالح للاستخدام مع الكرفس.

إغلاق هذا ، لأننا لا نملك الموارد لإكمال هذه المهمة.

حل ممكن"

كان لدي مثل هذه المهمة التي كانت تحاول إنشاء سلاسل رسائل وهذا سيفشل. تمكنت من تشغيله من خلال: التفرغ إلى برنامج نصي bash يتفرع هو نفسه إلى مترجم Python الذي يقوم بنفس الشفرة بالضبط (وبالتالي يمكنه إنشاء مؤشرات ترابط ، والتي كانت ضرورية لحالة الاستخدام الخاصة بي)

أنا لا أفهم سبب إغلاق التذكرة. إذا لم يكن لديك مورد لذلك ، فيمكنك تقديم تعليق حول هذا ، لكن هذا لا يغلق التذكرة. أنت فقط تخفي الخطأ أثناء القيام بذلك.

وهو أمر سيء بشكل خاص بالنسبة للبطاقة المصنفة "حرجة" من حيث الأولوية والخطورة.

orzel +1.
الأولوية: حرجة
درجة الخطورة: حرج
إغلاق هذا ، لأننا لا نملك الموارد لإكمال هذه المهمة.

هذه مزحة. إذا لم يكن لديك موارد الآن - فلا تقم بإصلاحها الآن. أصلحه عندما يكون لديك موارد. إغلاق التذكرة لن يزيل المشكلة

orzelTemplarrr أنا وصفت هذه التذكرة كما الحرجة حتىask ليس لإلقاء اللوم هنا.
قد تكون غير سعيد بهذا ، لكن الاحتجاج لن يساعدك.
نحن بحاجة إلى إعداد الأعمال المتراكمة لدينا استنادًا إلى ما هو قابل للتنفيذ وما هو ليس كذلك حاليًا.
إنها دعوة صعبة ولكن يجب على شخص ما القيام بها.
إذا كانت هذه المشكلة في طريقك ، فحاول إصلاحها. أعدك بأنه إذا كان الإصلاح صحيحًا ولديه الاختبارات المناسبة ، فسأدمجه.

thedrow
لقد اسأت الفهم. مرتين.
ما يقلقنا ليس أنك لا تمتلك المورد (هذا مفهوم تمامًا ، وللأسف ، حالة شائعة جدًا في البرمجيات الحرة). قلقنا هو أن التذكرة مغلقة بسبب ذلك ، فهذه ليست طريقة عمل التذاكر.
نحن لسنا "غير سعداء" ، نشعر بالصدمة.

كما أنني أختلف تمامًا مع إغلاق هذا.

أعتقد أننا يمكن أن نتفق جميعًا على أن هذا _ هو بالفعل خطأ. وعلى الرغم من أنه من المحزن حقًا عدم وجود موارد كافية ، فإن إغلاق خطأ _definite_ لن يساعد في هذا الأمر. ربما لا يمكنك معرفة ما إذا كان شخص ما قد يأتي بعيدًا في الغد ويفكر "لنصلح بعض الأخطاء في الكرفس" فقط للنظر في المشكلات المفتوحة والتفكير "حسنًا ، ليس هناك أي عمل مثير للاهتمام للقيام به هنا ... دعنا نعمل على _OtherProject_ بدلاً من ذلك ".
بالإضافة إلى ذلك ، سيؤدي إغلاق هذه المشكلة إلى زيادة صعوبة العثور عليها. لا أعرف كيف تستخدم Github ، لكن عندما أكتشف مشكلة محتملة ، أقوم أولاً بالبحث في أداة تعقب المشكلات عن المشكلة المفتوحة. عادةً ما يكون هناك الكثير من المناقشات وأكثر من ذلك ، لا يوجد حل بديل (كما في هذه الحالة) يمكنني استخدامه في الوقت الحالي. فقط إذا شعرت باليأس حقًا ، أبدأ في البحث في القضايا المغلقة.

هذا ليس "الاستمالة المتراكمة" إنه تعديل رقم. إذا نظرت إلى الأشياء التي يجب استخدامها ، فقم بإلقاء نظرة على عدد القضايا المفتوحة ولكني دائمًا ما ألقي نظرة على عدد النجوم (وهو مرتفع جدًا بالنسبة للكرفس). أتفهم أنه من المستحسن أن يكون عدد الأخطاء منخفضًا للاستئناف العام ولكن أيضًا لمصلحتك. بصراحة ، أنا أفهم أن رؤية "250 قضية مفتوحة" ليس عددًا جيدًا ويبدو أمرًا مربكًا.

إذا لم يكن لديك القوة البشرية للعمل على هذا في الشهر القادم (أو حتى العام) - فهذا جيد -. فقط لا تغلق. يجب أن يحدث الإغلاق فقط إذا تم حل المشكلة أو كان من الواضح تمامًا أنه لن يتم حل المشكلة أبدًا. كلاهما ليس هو الحال هنا.

ما عليك سوى إزالة العلامات "الحرجة" وإضافة علامة "مؤجل" لأي شيء لا يمكن التعامل معه الآن ولكن يجب التعامل معه إذا كان المورد _are_ متاحًا.

لست متأكدًا من أنه يمكننا بالفعل حل المشكلة. لا يمكننا تغيير طريقة عمل يونكس ولكن يمكننا إرسال تصحيح في اتجاه المنبع لرفع القيد؟

ربما توجد حلول خاصة بالنظام الأساسي في Linux ، ولكن يجب البحث في ذلك. لقد كان مفتوحًا لمدة عامين دون أن يكون لدى أي شخص الحافز لإصلاحه ، لذلك من غير المرجح أن يتم إصلاحه في الميزة القريبة.

لقد أغلقت أكثر من 200 إصدار ووضعت علامة على ما يزيد عن 30 ألف رسالة بريد إلكتروني مقروءة ، لذا لا بد أن بعضها مثير للجدل ، وقد نضطر إلى إعادة فتحها. أتوقع ذلك تمامًا ، ولكن بعد ذلك سيكون من الجيد أن نتمكن أيضًا من المساهمة في حل ، على سبيل المثال من خلال المساعدة في توثيق العيب إذا كان هذا هو الخيار الوحيد المعروف.

نحن غارقون في العمل ، نحاول تشغيل مشروع ضخم بدون موارد. لا يمكننا فرز المشكلات أو معرفة المشكلات التي تم إصلاحها بالفعل.

حسنا .. حسنا. ولكن هل يمكن توثيق حقيقة أنه "لا يمكنك استخدام المعالجة المتعددة إذا كتبت رمزًا لعامل كرفس" على الأقل؟ أعني ... سيكون هناك دائمًا أشخاص لا يقرؤونها ولكن على الأقل يمكنك الإشارة إليها وتقول "انظر ، إنها موثقة. لا يمكننا تغييرها. تعامل معها."

قائمة المهام الخاصة بي ضخمة ، يمكنك تحرير الوثائق مباشرة على جيثب الآن لذا من السهل حقًا المساهمة في تغييرات مثل هذه :(

لا أفعل هذا لإخفاء المشكلات ، فأنا أفعل ذلك لحث الناس على اتخاذ إجراءات على وجه التحديد لأنني أريد أن أراها تتحسن.

ask هل يمكننا تطبيق المعالجة المتعددة داخل المهمة باستخدام الكرفس في django؟
هل هناك أي بديل للقيام بذلك؟

abhisheksachan ، يجب أن تقرأ كل هذه المشكلة قبل نشر مثل هذا السؤال

abhisheksachan لم أجرب هذا في بضع سنوات ، لكنني نجحت في استخدامه باستخدام https://pypi.python.org/pypi/billiard لأنه يسمح بإضفاء الطابع الخفي على العمليات الفرعية.

نعم ، عليك استبدال الواردات من "المعالجة المتعددة" بـ "البلياردو" ، على سبيل المثال:

from multiprocessing import Process

->

from billiard import Process

لا توجد طريقة لنا لتعطيل قيود المعالجة المتعددة ، لكننا نجادل بأنه لا ينبغي أن يكون هناك قيود على أي حال ، لذا فإن شوكة المعالجة المتعددة لدينا تسمح بذلك.

بالنسبة لأي شخص مثلي ، استثمر في تطوير نظام قائمة انتظار _BEFORE_ اكتشف هذا القيد ويحتاج إلى حل مختلف حتى يتمكن من الانتقال إلى غلاف rabbitMQ python أكثر قابلية للاستخدام ، تمكنت من حل المشكلة عن طريق استدعاء عملية فرعية خارجية يمكنها شوكة نفسها نظيفة. هذه العملية المتشعبة الآن خارج صندوق رمل الكرفس وتعمل الأشياء كما ينبغي.

في مثال 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 ، لم ينجح حله ، حيث تقوم المعالجة المتعددة بفحص العملية وتمنعها من بدء الطفل.

تمكنت من رفع التقييد عن طريق إعادة تعيين العلم الخفي للعامل. أنا متأكد من أن هذه فكرة سيئة ، لكنها تسمح ببدء المعالجة المتعددة. أحواض السباحة من داخل مهمة الكرفس.

@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 ، لأنك تعلم أنك وصلت إلى نقطة يتعين عليك فيها إعادة تصميم التطبيق بالكامل. لكنه قيد على مستوى نظام التشغيل ، لا يمكنك التحايل عليه دون آثار جانبية خطيرة. عمليات Daemonic أيضًا لا يمكن أن يكون لها أطفال في C. هذه ليست أشياء خاصة بـ Python. كان هناك نقاش حول أداء العملية مقابل مؤشر الترابط ، وكما تبين الاستنتاج أنه لا يوجد أي منهما أفضل أو أسوأ بشكل ملحوظ من الآخر.

أقترح خيارين (والحديث بشكل عام ليس عن الكرفس هنا)

  • استخدم subprocess.Popen لإنشاء عملية مستقلة ، والتي يمكن أن يكون لها أطفال واستخدام مآخذ UNIX للتواصل بين العمليات
  • هل من الضروري حقًا أن يتم إنتاج الخيوط من خلال عملية متشعبة وليس العملية الرئيسية الخاصة بك؟

لما يستحق ، كانت حالة الاستخدام الخاصة بي في ذلك الوقت هي أنني أردت إطلاق عملية فرعية طويلة الأمد والتي غالبًا ما تتعطل بسرعة بسبب مشكلات الإدخال غير التافهة (وغير الحساسة للأمان). لذلك كانت الفكرة على الأقل التأكد من بدء العملية بنجاح.

اتضح على المدى الطويل أنه تصميم سيئ لأسباب مختلفة لذلك عادت الهندسة المعمارية الجديدة بشكل طبيعي إلى الاستخدام "الطبيعي" لعمال الكرفس غير المتزامن. لذلك أتفق مع فكرة التساؤل عما إذا كان التفرع ضروريًا حقًا ؛ المهمة _is_ مفترق الطرق.

لما يستحق ، كانت حالة الاستخدام الخاصة بي هي إطلاق عمليات 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 ، أحتاج إلى تمكين المعالجة المتعددة.

هل جربتم يا رفاق خدعة Unix المزدوجة القديمة للتبرؤ من الأطفال من عملية الكرفس الخفية؟

هل قرأت عنوان هذا الموضوع؟!؟!؟

من الواضح أن المزدوجة ، لكنني الآن أرى أن حيرتي كانت تفكر في أن الكرفس يقتل الشوك الخفي ، وليس أنه تم منعهم تمامًا.

مسكتك. نعم في حياتي السابقة كنت أستخدم C لذا كان هذا مثل الخبز والزبدة.

الحل الذي أستخدمه هو subprocess.Popen الذي يعمل بشكل جيد ولكن بعد ذلك تحتاج إلى إعادة تنفيذ بعض المنطق (وإنشاء نسخة من البرنامج) وهذا ما يجب أن يفعله الكرفس في المقام الأول. لكنني أصلحته عن طريق تغيير سلوك تنفيذ واجهة برمجة التطبيقات ذات المستوى الأعلى. إنه أكثر انسجامًا مع غرض الكرفس على ما أعتقد. تبسيط بعض المنطق حتى المستوى المنخفض.

لحسن الحظ find أجد هذه المشكلة عندما أحاول تشغيل كتاب قواعد اللعبة في مهمة الكرفس.
الطريقة التي قدمتها 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

أحاول إنتاج عملية باستخدام وحدة المعالجة المتعددة بيثون القياسية في الكرفس.

لا يُسمح للعمليات الخفية بإنشاء عمليات فرعية ، ونتيجة لذلك ، لا تعمل المهام التي تستخدم حزمة المعالجة المتعددة:
الأمر المستخدم للتشغيل: عامل الكرفس -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 التقييمات