Параллельная обработка в очереди (с использованием пула в Celery)

Я использую Celery для постановки в очередь заданий из CGI-приложения, которое я создал. Как я это настроил, Celery заставляет каждое задание выполняться по одному или по два за раз, устанавливая CELERYD_CONCURRENCY = 1 или = 2 (чтобы они не перегружали процессор и не тормозили из-за потребления памяти). Очередь отлично работает благодаря совету, который я получил на StackOverflow.

Каждое из этих заданий занимает довольно много времени (примерно 30 минут серийно), но имеет неприятную возможность распараллеливания. По этой причине я использовал Pool.map, чтобы разделить его и выполнять работу параллельно. Он отлично работал из командной строки, и я получил время работы около 5 минут, используя новый многоядерный чип.

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

AssertionError: демонические процессы не могут иметь потомков

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

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

Пара идей, которые у меня были (некоторые довольно хакерские):

  • The job sent to the Celery queue simply calls the command line program. That program can use Pool as it pleases, and then saves the result figures & data to a file (just as it does now).
    Downside: I won't be able to check on the status of the job or see if it terminated successfully. Also, system calls from CGI may cause security issues.
  • Obviously, if the queue is very full of jobs, I can make use of the CPU resources (by setting CELERYD_CONCURRENCY = 6 or so); this will allow many people to be "at the front of the queue" at once.
    Downside: Each job will spend a lot of time at the front of the queue; if the queue isn't full, there will be no speedup. Also, many partially finished jobs will be stored in memory at the same time, using much more RAM.
  • Use Celery's @task to parallelize within sub-jobs. Then, instead of setting CELERYD_CONCURRENCY = 1, I would set it to 6 (or however many sub jobs I'd like to allow in memory at a time).
    Downside: First of all, I'm not sure whether this will successfully avoid the "task-within-task" problem. But also, the notion of queue position may be lost, and many partially finished jobs may end up in memory at once.
  • Perhaps there is a way to call Pool.map and specify that the threads are non-daemonic? Or perhaps there is something more lightweight I can use instead of Pool.map? This is similar to an approach taken on another open StackOverflow question. Also, I should note that the parallelization I exploit via Pool.map is similar to linear algebra, and there is no inter-process communication (each just runs independently and returns its result without talking to the others).
  • Throw away Celery and use multiprocessing.Queue. Then maybe there'd be some way to use the same "thread depth" for every thread I use (i.e. maybe all of the threads could use the same Pool, avoiding nesting)?

Заранее большое спасибо.


person user    schedule 07.10.2011    source источник


Ответы (2)


arrow_upward
0
arrow_downward

Что вам нужно, так это система управления рабочим процессом (WFMS), которая управляет

  • параллелизм задач
  • зависимость задачи
  • вложение задач

среди прочего.

С точки зрения очень высокого уровня, WFMS находится поверх пула задач, такого как сельдерей, и отправляет задачи, готовые к выполнению, в пул. Он также отвечает за открытие гнезда и соответствующую отправку задач в гнездо.

Я разработал систему именно для этого. Он называется pomsets. Попробуйте и не стесняйтесь присылать мне любые вопросы.

person michael pan    schedule 12.10.2011
comment
Это похоже на Sun Grid Engine? Я надеялся использовать что-то изнутри Python. Еще лучше, я бы хотел, чтобы кто-нибудь сказал, что правильно (на питоне) делать в этой ситуации в целом. - person user; 16.10.2011
comment
Я бы сказал, что SGE больше похож на сельдерей, поскольку они оба управляют очередью задач. Пока библиотеки доступны, помсеты могут отправляться в celery, SGE или любую другую очередь выполнения. А pomsets написан на Python, так что вы можете создавать рабочие процессы прямо в своей программе на Python. - person michael pan; 17.10.2011
comment
Лучшим решением было создать Celery задания и использовать их для запуска других Celery заданий. Но, в конечном счете, этот ответ является самым близким - по сути, я решил проблему, используя Celery в качестве единственной WFMS. - person user; 28.03.2012
comment
Я разместил исходный код на GitHub github.com/mjpan/pomsets-core. - person michael pan; 19.09.2016

arrow_upward
0
arrow_downward

Я использую многопроцессорные демоны на основе Twisted с разветвлением и обычным запросом заданий Gearman.

Попробуйте посмотреть на Gearman.

person Michael_XIII    schedule 16.10.2011
comment
Я не делал эту задачу, но думал, что они должны это сделать. Если попробуете - держите меня в курсе о результате. - person Michael_XIII; 17.10.2011