将 django ORM 与多处理一起使用?

Posted

技术标签:

【中文标题】将 django ORM 与多处理一起使用?【英文标题】:Use django ORM with multiprocessing? 【发布时间】:2018-03-10 02:20:39 【问题描述】:

我有一个 Django ORM 数据库(mysql 或 sqlite),并希望通过计算密集型操作来处理每一行。我现在拥有的是这样的:

entries = Entry.objects.filter(language='')
for e in entry:
    e.language = detect_language(e.text)
    e.save()

如果数据库是瓶颈,我会使用事务来加速它。但是,detect_language 函数花费的时间最多。我可以尝试多次并行运行脚本,但这会引入竞争条件。

我认为这可以通过 multiprocessing 使用 Pool.map() 来完成 - 主进程获取数据库条目,子进程运行 detect_language。我不知道如何详细地做到这一点,例如是否将条目保存在子进程或主进程中。

在进程之间传递 ORM 对象时有什么需要注意的吗?您能否举一个简短的例子,如何将 ORM 与多处理一起使用?

我刚刚绑定了它,像这样的东西似乎工作正常。我仍然想知道这里是否有任何警告,或者这是否可以提高性能(例如批处理数据库更新):

def detect_and_save(obj):
    obj.language = detect_language(obj.text)
    obj.save()

with multiprocessing.Pool(processes=3) as pool:
    pool.map(detect_and_save, entries)

【问题讨论】:

此操作是在线运行还是离线运行(例如在 Celery 任务中)? 离线,即在脚本中 (import myapp.wsgi)。最终我可能会使用像 Celery 这样的东西,但目前为了测试我使用的是最简单的东西。 【参考方案1】:
    您无需传递完整的 ORM 对象 - 您只需传递函数所需的参数并将其结果保存到 ORM 对象即可。 您可以使用 bulk_update(可从 Django 2.2 获得或作为 3rd party library)保存在单个查询中。
texts = [e.text for e in entries]
with multiprocessing.Pool() as pool:
    languages = pool.map(detect_language, texts)
for e, l in zip(entries, languages):
    e.language = l
Entry.objects.bulk_update(entries, ['language'])

【讨论】:

以上是关于将 django ORM 与多处理一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

与多处理一起使用时,PyTesseract 调用工作非常缓慢

与多处理和共享变量一起运行两个函数

Apache camel 错误处理如何与多播和事务一起使用

Django 之 ORM表之间的外键关联与多对多

cProfiler 与多处理一起工作很奇怪

C - SIGINT处理程序不能与多线程一起工作,每个线程都有一个popen进程。