Celery workers未填满并发槽位
我有一个工作者,能够同时处理4个任务。我在flower上看到启动了4个进程,一切看起来都很好。
如果我在命令行中执行这个操作,我会看到4个工作者开始接任务,其他的任务被保留,它们会同时处理4个任务,直到队列里的任务处理完。
[my_task.apply_async() for i in xrange(10)]
但是如果我逐行执行,只有前两个任务被积极处理,从那以后它们每次只处理两个任务。
my_task.apply_async()
my_task.apply_async()
my_task.apply_async()
my_task.apply_async()
...
有什么想法吗?
1 个回答
3
通常,这种情况是因为子进程占满了并发的名额。Celery 默认使用预分叉(prefork)作为执行池,每次你启动一个任务的子进程(也就是另一个分叉),它就会算作一个正在运行的进程,从而占用一个并发名额。
避免这种情况最简单的方法是 使用 eventlet,这样你可以在每个任务中同时处理多个异步调用。不过,这要求你的任务中不能有阻塞的调用,比如 subprocess.communicate
,因为这些会阻塞所有任务。
如果你确实需要阻塞调用,并且知道你的任务一次只会有一个正在运行的子进程,你可以把 CELERYD_CONCURRENCY
设置为两倍(8
),并给你的任务设置一个开始时间限制,这样就不会立即启动8个任务(例如,使用 @app.task(rate_limit='10/m')
)。不过,这有点像是变通的方法,使用 eventlet 绝对是更好的选择。