Celery: Tugas tidak diperbolehkan untuk memulai subproses

Dibuat pada 29 Nov 2013  ·  68Komentar  ·  Sumber: celery/celery

Dimulai dengan Celery 3.1.0 kumpulan proses ( celery.concurrency.prefork , sebelumnya celery.concurrency.processes ) menggunakan proses daemon untuk melakukan tugas.

Proses daemon tidak diizinkan untuk membuat proses anak dan, akibatnya, tugas yang menggunakan paket multiprocessing tidak berfungsi:

[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

Komentar yang paling membantu

@tokopedia
Kamu salah paham. Dua kali.
Perhatian kami bukanlah bahwa Anda tidak memiliki sumber daya (ini sangat dapat dimengerti, dan, sayangnya, kasus yang sangat umum dalam perangkat lunak bebas). Kekhawatiran kami adalah tiket ditutup karena itu, ini bukan cara kerja tiket.
Kami bukannya 'tidak bahagia', kami terkejut.

Semua 68 komentar

Ini tidak berubah antara 3.0 dan 3.1, jadi saya tidak yakin mengapa Anda mendapatkan kesalahan ini sekarang dan bukan sebelumnya.

Beginilah cara kesalahan ini direproduksi.

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()

Saya menjalankan pekerja menggunakan perintah berikut: celery worker -A app.app -l debug .

Dengan Celery 3.0.24 tugas berhasil:

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

Dengan Celery 3.1.5 tidak:

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

Pemahaman saya tentang masalah ini adalah sebagai berikut: celery.concurrency.prefork.TaskPool using celery.concurrency.asynpool.AsynPool ; AsynPool mewarisi dari billiard.pool.Pool yang memunculkan proses pekerja daemon dan AsynPool tidak menimpa perilaku ini. Tapi Anda benar, skema ini sepertinya tidak diubah antara 3.0 dan 3.1, jadi saya juga bingung :)

Dan sepertinya saya tidak sendirian dengan masalah itu: http://stackoverflow.com/questions/20149421/threads-in-celery-3-1-5

Satu perbedaan adalah bahwa proses pekerja sekarang merupakan subkelas dari 'Proses', di mana sebelumnya menggunakan argumen fungsi: Process(target=) , mungkin ada perbedaan nilai default untuk pendekatan ini.

multiprosesing dan versi lama set biliar daemon=True :
https://github.com/celery/billiard/blob/2.7/billiard/pool.py#L904

Dan itu sama di versi terbaru:
https://github.com/celery/billiard/blob/3.3/billiard/pool.py#L1039

Saya pikir proses tugas menjadi daemon menghadirkan batasan serius untuk implementasi tugas.
Saya menulis tugas yang menggunakan multiprocessing untuk mempercepat operasi yang terikat dengan CPU. Semuanya berfungsi dengan baik ketika saya memulai pekerja di terminal sebagai berikut:

pekerja seledri --app = tugas -Q wb -l info --concurrency = 1

Tetapi ketika saya menggunakan skrip seledri untuk memulai seorang pekerja, saya mendapatkan pengecualian ini:
AssertionError: proses daemonik tidak boleh memiliki anak

Saya menemukan apa yang menyebabkan perubahan perilaku.
Tugas dijalankan menggunakan proses daemon baik di 3.0 dan 3.1, tetapi hingga modul celery / billiard @ 4c32d2e dan https://github.com/celery/billiard/commit/c676b94aa4144349b11ab31c82296a5d804909c9 multiprocessing tidak menyadarinya dan karenanya memungkinkan pembuatan subproses.

Menurut pemahaman saya, ada bug sebelum versi 3.1 (tugas diizinkan untuk membuat subproses, yang dapat mengakibatkan status yatim piatu) dan sekarang bug ini telah diperbaiki.

Keputusan untuk tidak mengizinkan proses daemon python untuk bercabang tampaknya agak sewenang-wenang bagi saya. Sementara saya menyadari itikad baiknya, saya merasa saya harus dapat memiliki kendali penuh atas perilaku ini jika saya mau.

Terikat pada satu proses per tugas tampaknya menjadi batasan serius bagi saya. Pikiran?

Saya bertanya-tanya mengapa batasan itu ada di tempat pertama, peringatan yang bisa saya mengerti tetapi langsung melarangnya tampak konyol ketika Anda mampu melakukan proses dengan cara lain dengan sempurna.

@ask , apakah mungkin untuk menginisialisasi proses pekerja seledri dengan flag daemon menjadi False? Atau buat ini dapat dikonfigurasi?

@ilyastam sepertinya kami berkomentar bersamaan

Saya setuju bahwa ini sepertinya batasan yang sewenang-wenang, tetapi saya berharap saya tahu alasan di balik menambahkannya sejak awal.

Ini adalah perangkap yang terkenal dalam sistem posix, tetapi masih diperbolehkan. Anda dapat membersihkan proses anak dalam penangan sinyal, meskipun itu tidak melindungi Anda dari SIGKILL.

Saya pikir kita harus menghilangkan batasan dari biliar, meskipun itu akan menyimpang dari perilaku multiprosesing. Anda masih dapat membuat proses anak menggunakan modul subpocess atau menggunakan panggilan tingkat rendah fork , sehingga pengguna yang ahli harus dapat membuat instance anak billiard.Process .

@ilyastam Harus dapat menghapus pernyataan kenaikan, tidak harus membuat proses "non-daemon"

Artinya, proses daemon akan diizinkan untuk membuat proses anak meskipun tidak dapat menuai,
begitulah cara kerja posix.

Btw, perhatikan bahwa ini bukan raise , ini adalah pernyataan assert, yang akan dihapus jika python dimulai dengan argumen PYTHONOPTIMIZE envvar atau -O .

billiard 3.3.0.11 ada di PyPI termasuk perubahan ini

@tanyakan terima kasih. Tahu versi seledri apa yang akan mengalami peningkatan ini?

multiprocessing dokumentasi secara eksplisit menyatakan bahwa proses daemon tidak diperbolehkan untuk membuat subproses dan menjelaskan alasannya. Seperti untuk saya, ini assert pernyataan terlihat lebih seperti itu dimasukkan di sini sebagai jalan pintas untuk raise (orang sering melakukan hal itu).

Batasan ini didokumentasikan dan menurut saya bukan ide yang baik bagi Celery untuk diam-diam menambal multiprocessing dan menghapusnya. Ini dapat menyebabkan konsekuensi yang sangat tidak terduga dan berbahaya.

Saya dapat memikirkan contoh berikut (meskipun mungkin tampak sedikit dibuat-buat):

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

Dijalankan sebagai fungsi Python biasa, kode ini bekerja dengan benar. Tetapi dijalankan sebagai tugas Celery (menggunakan Celery versi 3.0. *), Meninggalkan tiga subproses yang akan hang selamanya; ketika pekerja Celery berhenti, subproses ini akan menjadi yatim piatu.

Itu tidak menjelaskan mengapa, itu hanya menyatakan perilaku unix yang Anda harapkan ketika memulai proses anak-anak. Meskipun itu adalah batasan terkenal dalam unix, itu tidak menghentikan orang untuk melakukannya. Ini tidak berbeda dengan
memulai proses subprocess.Popen , atau bahkan menelepon fork() untuk memulai proses baru. Jadi mengapa itu ilegal?

Cara melakukan contoh Anda:

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()

Untuk mematikan (-9) ini, Anda juga harus mematikan -9 proses anak, tetapi itu adalah sesuatu yang akan Anda miliki
untuk dipertimbangkan untuk semua proses unix.

Bukannya saya menganjurkan membuat Pool untuk setiap tugas, tapi saya tidak mengerti mengapa pengguna, yang tahu apa mereka
melakukan, seharusnya tidak diizinkan untuk melakukan proses memulai dari suatu tugas.

Juga, kami tidak menambal apa pun, ini hanya perubahan dalam biliar.

Juga, kami tidak menambal apa pun, ini hanya perubahan dalam biliar.

Yang saya maksud dengan "penambalan monyet" adalah tugas ini, yang menggantikan multiprocessing._current_process dengan contoh billiard.process.Process : https://github.com/celery/billiard/blob/master/billiard/process.py # L53.

Saya setuju bahwa tidak ada yang salah dengan memulai proses anak-anak jika ditangani dengan benar (seperti dalam contoh Anda). Maksud saya adalah bahwa multiprocessing tidak ditulis seperti itu dan kita tidak boleh mengabaikan batasan _implementation_ itu.

@aromanovich Tidak dapat ditulis dengan cara lain, itu bukan batasan multiprosesing, itu batasan unix.

Ini menyetel _current_process sehingga variabel logging modul processName format berfungsi, dan objek proses biliar memiliki API yang sama dengan objek proses multiproses sehingga aman untuk menyetel proses saat ini.

Dan btw, Anda harus menggunakan billiard untuk menghilangkan batasannya, menggunakan multiprocessing akan tetap memunculkan pengecualian.

Bisa juga memperbaiki masalah ini menggunakan pendekatan ini:
http://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic
Yang akan memungkinkan pengguna untuk terus menggunakan modul multiprosesing, menghindari masalah ini:
https://github.com/celery/billiard/issues/99

Saya mendapatkan kesalahan ini saat memanggil tugas kain @parallel dari dalam tugas seledri.

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

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

@rodopwn menggunakan ENV
ekspor PYTHONOPTIMIZE = 1
untuk menghapus pernyataan ini. Anda perlu menangani semua hal.

@xiaods Saya rasa saya memecahkan masalah itu dengan sesuatu seperti ini:

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

Masalah

Saya memiliki tugas yang menghitung beberapa data dan memuat pengklasifikasi scikit-learn untuk membuat prediksi berdasarkan data itu. Ketika saya menjalankan tugas itu sendiri, semuanya baik-baik saja, tetapi ketika saya menjalankannya menggunakan Celery, saya mendapatkan kesalahan saat tugas mencoba memuat pengklasifikasi acar:

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

Untuk mereproduksi

Buat pengklasifikasi kosong dan simpan sebagai acar:

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

Buat aplikasi sederhana ( 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)

Mulai pekerja seledri:

celery -A app worker --loglevel=debug

Jalankan aplikasi:

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

Pesan eror:

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

Larutan

Saya pikir harus ada opsi untuk "monkeypatch" Celery untuk memungkinkan tugas memulai sub-proses, terutama jika "fitur" seperti itu ada di masa lalu. Saat ini, orang-orang beralih ke framework lain ketika mereka menghadapi masalah ini: http://stackoverflow.com/questions/27904162/using-multiprocessing-pool-from-celery-task-raises-exception. Berikut adalah contoh lain dari kesalahan ini: http://stackoverflow.com/questions/22674950/python-multiprocessing-job-to-celery-task-but-attributeerror.

Masalah ini harus dibuka kembali ...

Saya baru saja mengalami masalah yang sama. Saya menggunakan nltk di dalam salah satu pekerja saya yang kemudian mengimpor scikit-learn yang mengarah ke kesalahan yang sama yang ditunjukkan @ostrokach .

Sepertinya saya bisa mengatasinya dengan kode berikut:

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

Ini jelas merupakan peretasan yang sangat kasar dan saya tidak tahu apa yang akan terjadi jika saya benar-benar menggunakan multiprosesing (sih, saya bahkan tidak tahu apa itu semprefix ) tetapi itu cukup untuk menghasilkan scikit-learn bekerja lagi.

Saya meninggalkan ini di sini untuk orang lain yang tersandung masalah yang sama sampai masalah ini diperbaiki.

Mungkinkah ini semacam ketidakcocokan dengan biliar di Python 3? Atau apakah itu dapat direproduksi pada Python 2 juga?

Apakah masalah asli proses seledri tidak mampu membuat subproses masih menjadi masalah? Melihat kembali komentar, telah diperbaiki dengan celery / billiard @ e6bb0f7 untuk versi 3.3. Namun kemudian commit (celery / billiard @ c7eedbd0ee1498e76d4fa1affac5b1a275660ee7) memperkenalkan kembali pernyataan assert yang sangat mirip ke dalam metode start untuk 3.4. Tidak ada masalah bagi saya karena saya menggunakan versi 3.3, tetapi hanya ingin menunjukkan jika hal itu dapat menimbulkan masalah di masa mendatang.

@martinth Terima kasih,

@xiaods Terima kasih! Solusi Anda berhasil untuk saya! Terima kasih!

@gilinson itu masih menjadi masalah dan ekspor PYTHONOPTIMIZE = 1 masih "agak memperbaikinya".
Baru saja mengalami masalah yang sama, mencoba menjalankan buku pedoman yang memungkinkan dalam tugas Celery

@martinth Terima kasih atas

  • Python 3.4.3
  • seledri == 3.1.18
  • scikit-learn == 0,17

Retasan @martinth tidak berfungsi untuk saya, mengalami ini saat mencoba menggunakan multiprosesing untuk mempercepat beberapa komputasi. Menggunakan modul threading sebagai gantinya dan tampaknya meringankan kesalahan ini untuk saya saat masih menghentikan pemrosesan saya.

Menggunakan multiprocessing.dummy berbasis utas bekerja di seledri untuk saya:

from multiprocessing.dummy import Pool

Kesalahan ini masih terjadi di python 2.7.5 juga. Saya tidak yakin apakah itu dimaksudkan untuk mengatasinya, tetapi ini membuat penggunaan saltstack's salt-ssh tidak dapat digunakan dengan seledri.

Menutup ini, karena kami tidak memiliki sumber daya untuk menyelesaikan tugas ini.

"Solusi" yang mungkin

Saya memiliki tugas seperti itu yang mencoba membuat utas dan ini akan gagal. Saya berhasil membuatnya bekerja dengan: bercabang ke skrip bash yang dengan sendirinya bercabang ke penerjemah python yang melakukan kode persis sama (dan karenanya dapat membuat utas, yang sangat penting untuk kasus penggunaan saya).

Saya tidak mengerti mengapa tiket ditutup. Jika Anda tidak memiliki sumber daya untuk itu, Anda dapat membuat komentar tentang ini, tetapi ini tidak menutup tiket. Anda hanya menyembunyikan bug dengan melakukannya.

Yang sangat buruk untuk tiket berlabel "kritis 'baik untuk prioritas maupun tingkat keparahan.

@orzel +1.
Prioritas: Kritis
Keparahan: Kritis
Menutup ini, karena kami tidak memiliki sumber daya untuk menyelesaikan tugas ini.

Itu lelucon. Jika Anda tidak memiliki sumber daya sekarang - jangan perbaiki sekarang. Perbaiki saat Anda memiliki sumber daya. Menutup tiket tidak akan menghilangkan masalah

@orzel @Templarrr Saya memberi label tiket ini sebagai Kritis sehingga @ask tidak bisa disalahkan di sini.
Anda mungkin tidak senang tentang ini, tetapi memprotes tidak akan membantu.
Kita perlu mengatur backlog kita berdasarkan apa yang dapat ditindaklanjuti dan apa yang tidak dan saat ini tidak.
Ini panggilan yang sulit untuk dilakukan tetapi seseorang harus membuatnya.
Jika masalah ini menghalangi Anda, coba perbaiki. Saya berjanji bahwa jika perbaikannya benar dan memiliki tes yang sesuai, saya akan menggabungkannya.

@tokopedia
Kamu salah paham. Dua kali.
Perhatian kami bukanlah bahwa Anda tidak memiliki sumber daya (ini sangat dapat dimengerti, dan, sayangnya, kasus yang sangat umum dalam perangkat lunak bebas). Kekhawatiran kami adalah tiket ditutup karena itu, ini bukan cara kerja tiket.
Kami bukannya 'tidak bahagia', kami terkejut.

Saya juga sangat tidak setuju dengan penutupan ini.

Saya rasa kita semua setuju bahwa _is_ ini memang bug. Dan meskipun memang menyedihkan bahwa tidak ada cukup sumber daya menutup bug _definite_ tidak akan membantu ini. Anda tidak mungkin tahu apakah mungkin besok seseorang datang lama dan berpikir "mari kita perbaiki beberapa bug di Celery" hanya untuk melihat melalui masalah terbuka dan berpikir "Yah, tidak ada pekerjaan menarik untuk dilakukan di sini ... ayo bekerja di _OtherProject_ sebagai gantinya ".
Selain itu, menutup masalah ini akan membuat lebih sulit untuk menemukannya. Saya tidak tahu bagaimana Anda menggunakan Github, tetapi ketika saya menemukan potensi masalah, saya pertama kali mencari pelacak masalah untuk masalah terbuka. Biasanya ada banyak diskusi dan lebih banyak lagi tidak pernah ada solusi (seperti dalam kasus ini) yang bisa saya gunakan untuk saat ini. Hanya jika saya benar-benar _sangat putus asa, saya mulai melihat-lihat masalah yang telah ditutup.

Ini bukan "perawatan backlog" itu adalah mengutak-atik nomor. Jika saya melihat hal-hal yang akan digunakan, saya _do_ melihat jumlah masalah terbuka tetapi saya juga selalu melihat jumlah bintang (yang cukup tinggi untuk seledri). Saya memahami bahwa Anda ingin memiliki jumlah bug yang rendah untuk daya tarik publik, tetapi juga untuk kepentingan Anda sendiri. Sejujurnya, saya mengerti bahwa melihat "250 masalah terbuka" bukanlah angka yang bagus dan terdengar berlebihan.

Jika Anda tidak memiliki tenaga untuk mengerjakan ini di bulan depan (atau bahkan tahun) _ini bagus_. Jangan tutup. Penutupan hanya akan terjadi jika masalah telah selesai atau _sangat jelas_ bahwa _tidak pernah_ akan selesai. Keduanya tidak terjadi di sini.

Hapus saja tanda "Kritis" dan tambahkan tanda "Ditunda" untuk apa pun yang tidak bisa ditangani sekarang, tetapi harus ditangani jika sumber daya _are_ tersedia.

Saya tidak yakin kami benar-benar dapat memperbaiki masalah tersebut. Kami tidak dapat mengubah cara kerja unix tetapi kami dapat mengirimkan tambalan ke hulu untuk mencabut batasan?

Mungkin ada solusi khusus platform di Linux, tetapi itu harus diteliti. Sudah terbuka selama 2 tahun tanpa ada yang memiliki insentif untuk memperbaikinya, jadi tidak mungkin diperbaiki dalam fitur dekat.

Saya menutup 200+ masalah dan menandai lebih dari 30 ribu email sebagai telah dibaca, jadi beberapa di antaranya pasti kontroversial, dan kami mungkin harus membukanya kembali. Saya benar-benar mengharapkan itu, tetapi alangkah baiknya jika kita juga dapat berkontribusi pada solusi, misalnya dengan membantu mendokumentasikan cacat jika itu adalah satu-satunya pilihan yang diketahui.

Kami dibanjiri pekerjaan, mencoba menjalankan proyek besar tanpa sumber daya. Kami tidak dapat melakukan triase masalah atau mencari tahu masalah apa yang telah diperbaiki.

Baiklah..baiklah. Tetapi dapatkah fakta bahwa "Anda tidak dapat menggunakan multiprosesing jika Anda menulis kode untuk pekerja seledri" setidaknya dapat didokumentasikan? Maksud saya ... akan selalu ada orang yang tidak membacanya tetapi setidaknya Anda dapat menunjukkannya dan berkata, "Lihat, ini didokumentasikan. Kami tidak dapat mengubahnya. Atasi."

Daftar rencana saya sangat besar, Anda dapat mengedit dokumentasinya langsung di github sekarang jadi sangat mudah untuk memberikan kontribusi perubahan seperti ini :(

Saya tidak melakukan ini untuk menyembunyikan masalah, saya melakukan ini untuk membuat orang bertindak justru karena saya ingin melihatnya membaik.

@ask Bisakah kita menerapkan tugas multiproses di dalam menggunakan seledri di django?
Apakah ada alternatif lain untuk melakukannya?

@abhisheksachan Anda harus membaca semua masalah ini sebelum memposting pertanyaan seperti itu

@abhisheksachan Saya belum mencoba ini dalam beberapa tahun, tetapi saya berhasil menggunakan https://pypi.python.org/pypi/billiard karena memungkinkan daemonisasi subproses.

Ya, Anda harus mengganti impor dari 'multiprocessing' dengan 'billiard', misalnya:

from multiprocessing import Process

->

from billiard import Process

Tidak ada cara bagi kami untuk menonaktifkan batasan multiprosesing, tetapi kami berpendapat seharusnya tidak ada batasan sehingga garpu multiprosesing kami mengizinkannya.

Bagi siapa saja, yang seperti saya, berinvestasi dalam mengembangkan sistem antrian _BEFORE_ mencari tahu tentang batasan itu dan membutuhkan solusi yang berbeda sampai mereka dapat bermigrasi ke pembungkus python RabbitMQ yang lebih bisa digunakan, saya berhasil mengatasi masalah ini dengan memanggil subproses eksternal yang dapat garpu itu sendiri dengan bersih. Proses bercabang itu sekarang berada di luar kotak pasir seledri dan semuanya berfungsi sebagaimana mestinya.

Dalam contoh OP, ganti:

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

dengan:

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

dan "program" akan terlihat seperti (di bawah platform 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)

Ingatlah bahwa manajemen CPU keluar dari lingkup seledri yang agak bertentangan dengan gagasan menggunakan seledri, tetapi mengingat Anda akan menggunakan multiprosesing, Anda mungkin ingin menangani penggunaan CPU di luar seledri.

Setidaknya batasan itu harus didokumentasikan. Saya melihat sekeliling di dokumen dan tidak dapat menemukan.

Sekali lagi, jangan ragu untuk mengirimkan permintaan penarikan dengan perubahan dokumentasi.

menindaklanjuti komentar @martinth , pada Python 3.5.2, Celery 4.0.0 dan billiard 3.5.0 solusinya tidak berfungsi, karena pemeriksaan multiprosesing pada proses yang sedang daemonisasi dan menghentikannya dari memulai anak.

Saya bisa mencabut batasan dengan mengatur ulang bendera daemon pekerja. Saya cukup yakin itu ide yang buruk, tetapi ini memungkinkan memulai multiproses. Alat dari dalam tugas seledri.

@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

Karena itu, IMHO Celery harus menambahkan opsi terdokumentasi untuk mengonfigurasi apakah itu memulai pekerja sebagai deamons. Catatan Saya menggunakan seledri dalam pod k8 sehingga seledri dimulai sebagai proses latar depan dengan menggunakan celery worker , dan saya benar-benar tidak membutuhkan pekerja daemonisasi.

@miraculixx Masalah dengan saran ini adalah kita akan memiliki lebih banyak mode gagal untuk ditangani dan lebih banyak masalah untuk diatasi. Kami lebih suka menghindari itu.

Meskipun penggunaan multiprosesing gagal dalam kombinasi dengan kumpulan prefork, tampaknya berfungsi saat menggunakan kumpulan solo. Jadi saya kira solusinya adalah menelurkan beberapa pekerja seledri dengan kolam tunggal, alih-alih satu dengan banyak anak di kolam prefork. Apakah ini terdengar sah? Tentu saja dengan cara itu beberapa opsi seperti max-mem-per-child tidak akan berfungsi.

Saya rasa ini pada dasarnya adalah masalah desain aplikasi. Sungguh menyakitkan menghadapi daemonic processes are not allowed to have children , karena Anda tahu, Anda mencapai titik ketika Anda harus mendesain ulang seluruh aplikasi. Tetapi ini adalah batasan level OS, Anda tidak dapat mengelak tanpa efek samping yang serius. Proses daemonic juga tidak dapat memiliki anak di C. Ini bukan hal khusus Python. Dulu ada perdebatan tentang kinerja thread vs proses, dan sebagai kesimpulannya ternyata tidak ada yang secara signifikan lebih baik atau lebih buruk dari yang lain.

Saya menyarankan dua opsi (dan berbicara secara umum, bukan tentang seledri di sini)

  • Gunakan subprocess.Popen untuk menelurkan proses independen, yang dapat memiliki anak dan menggunakan soket UNIX untuk komunikasi antar-proses
  • Apakah benar-benar perlu agar utas muncul dengan proses bercabang dan bukan proses utama Anda?

Untuk apa nilainya, kasus penggunaan saya saat itu adalah bahwa saya ingin meluncurkan subproses yang berjalan lama yang sering macet dengan cepat karena masalah input yang tidak sepele (dan tidak sensitif terhadap keamanan). Jadi idenya adalah untuk setidaknya memastikan proses diluncurkan dengan sukses.

Ternyata dalam jangka panjang menjadi desain yang buruk karena berbagai alasan sehingga arsitektur baru secara alami kembali ke penggunaan "alami" pekerja seledri asinkron. Jadi saya setuju dengan gagasan mempertanyakan apakah garpu benar-benar diperlukan; tugas _adalah garpu.

untuk apa nilainya, kasus penggunaan saya adalah meluncurkan proses scikit-learn yang menggunakan multiprosesing (melalui joblib). Saya telah mengembangkan backend seledri ke joblib yang berarti scikit-learn meluncurkan proses paralel menggunakan seledri dan peretasan saya di atas tidak lagi diperlukan. Ini dalam tahap POC, belum siap untuk prime-time.

@miraculixx Apakah Anda memiliki

@pgeez Jika Anda tidak peduli tentang penggunaan subproses di sklearn, Anda dapat menyetel variabel lingkungan JOBLIB_MULTIPROCESSING = 0. Lihat https://github.com/scikit-learn/scikit-learn/blob/0.18.X/sklearn/externals/joblib/_multiprocessing_helpers.py

@Jennaliu terima kasih atas pemikirannya, tetapi seperti @miraculixx , saya perlu mengaktifkan multiproses.

Sudahkah kalian mencoba trik garpu ganda Unix lama untuk menolak anak-anak dari proses daemon seledri?

Apakah Anda membaca judul utas ini?!?!?

@sebastroy jelas, saya telah mengikuti utas ini selama bertahun-tahun. Saya baru saja menemukan garpu ganda , tetapi sekarang saya melihat kebingungan saya adalah berpikir bahwa garpu daemon dibunuh oleh seledri, bukan dicegah secara langsung.

Kena kau. Ya di kehidupan saya sebelumnya, saya menggunakan C jadi ini seperti roti dan mentega.

Solusi yang saya gunakan adalah subprocess.Popen yang berfungsi dengan baik tetapi kemudian Anda perlu menerapkan ulang beberapa logika (dan membuat versi shell dari program) itulah yang seharusnya dilakukan seledri. Tapi saya memperbaikinya dengan mengubah perilaku implementasi API tingkat atas. Menurut saya, ini lebih sesuai dengan tujuan seledri. Sederhanakan beberapa logika juga pada level rendah.

Untungnya, saya menemukan masalah ini ketika saya mencoba menjalankan buku pedoman yang memungkinkan dalam tugas Celery.
Metode yang disediakan oleh @martinth tidak berhasil untuk saya. Saya mencetak current_process()._config dan mendapatkan
{'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} .
Kemudian saya menetapkan kembali bidang daemon menjadi False , dan berhasil.

Apakah ada solusi atau implementasi lain untuk memungkinkan menjalankan multiproses dalam tugas?

@HeartUnchange : baru-baru ini kami sedang mengerjakan proyek big data, yang ingin menggunakan seledri sebagai komponen terdistribusi. dan dengan pemandu Anda, kami sangat beruntung bisa menyelesaikan masalah. lihat konfigurasi tugas:

     @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))

Solusinya ok! kami memulai proyek pada 2017.1 dan sekarang prototipe selesai! sembilan bulan telah berlalu! Saya mengucapkan terima kasih kepada Anda! dan terima kasih saya melampaui ekspresi!
tolong jelaskan lebih lanjut tentang bagaimana Anda memecahkan masalah! kami sangat ingin tahu itu!

Hai,

Saya memiliki pengaturan yang cukup standar: Django + Rabbitmq + celery-4.0.2 + python-2.7 + centOS-7

Saya mencoba menelurkan proses menggunakan modul multiprocessing python standar dalam seledri.

Proses daemon tidak diizinkan untuk membuat proses anak dan, akibatnya, tugas yang menggunakan paket multiprosesing tidak berfungsi:
Perintah yang digunakan untuk menjalankan: pekerja seledri -B -A celery_task -l debug
Traceback Logs:

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

Apa yang bisa menjadi alasan untuk tidak melakukan proses pemijahan?
Ini kodenya:

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()

Terimakasih.

coba master dan laporkan jika masih masalahnya

Masih ada kesalahan. Saya mencoba menggunakan subproses dengan:

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()

Tapi dengan cabang master seledri itu sais:

File "/usr/lib/python3.5/multiprocessing/process.py", baris 103, di awal
'proses daemonik tidak boleh memiliki anak'
AssertionError: proses daemonik tidak boleh memiliki anak

EDIT

Saya mengubah multiprosesing dengan biliar dan berhasil!

from billiard import Process, Value

Apakah halaman ini membantu?
0 / 5 - 0 peringkat