使用多处理池更新 django 模型会锁定数据库

abo*_*nov 3 python django postgresql multiprocessing jupyter-notebook

我使用 Jupyter Notebook 来处理我存储在 django/postgres 中的数据。我以这种方式初始化我的项目:

sys.path.append('/srv/gr/prg')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'prg.settings')
if 'setup' in dir(django):
    django.setup()
Run Code Online (Sandbox Code Playgroud)

有许多更新数据的独立进程,我想多线程处理它以加快进程。当我在单个线程中进行更新或使用时,一切正常sqlite.

def extract_org_description(id):
    o = models.Organization.objects.get(pk=id)
    logging.info("Looking for description for %s" % o.symbol)
    try:
        content = open('/srv/data/%s.html' % o.symbol)
    except FileNotFoundError:
        logging.error("HTML file not found for %s" % o.symbol)
        return
    doc = BeautifulSoup(content, 'html.parser')
    desc = doc.select("#cr_description_mod > div.cr_expandBox > div.cr_description_full.cr_expand")
    if not desc or not desc[0]:
        logging.info("Cannot not find description for %s" % o.symbol)
        return
    o.description = desc[0].text
    o.save(update_fields=['description'])
    logging.info("Description for %s found" % o.symbol)
    return("done %s" % id)
Run Code Online (Sandbox Code Playgroud)

这将不起作用:

p = Pool(2)
result = p.map(extract_org_description, orgs)
print(result)
Run Code Online (Sandbox Code Playgroud)

大多数情况下,它会挂起直到我中断它,没有任何特定错误,有时 postgres 会出现“已经有一个事务在进行中”,有时我会看到“没有结果可获取”错误。玩池大小我可以让它工作一两次,但很难诊断到底是什么问题。

我尝试将策略更改为选择对象并将它们映射到 extract_org_description将对象作为参数的(不同于基于键的选择),但这并没有更好的效果。

我唯一的想法是,当 django 尝试自动提交时,所有单独的更新,包括其他线程中发生的更新,都在同一事务范围内,这导致了问题。但我不明白如何在 Django 中解决这个问题。

Kev*_*nry 5

您的问题包括术语multiprocessingmultithread,但重要的是要了解这些是实现并发的不同方式。

Django 内置了对多线程的支持,并且会为每个线程创建一个新的数据库连接。如果您从多处理切换到多线程,您的问题应该得到解决。

在多处理中,整个进程被分叉,新进程将与旧进程具有相同的数据库连接。这会导致您所看到的问题,例如,当另一个进程已在同一数据库连接上打开一个新事务时,您尝试打开一个新事务。

如果您确实需要多处理而不是多线程,则可能有解决方案。例如,这个答案建议简单地关闭数据库连接,强制 Django 创建新的连接。