簡體   English   中英

Python SQLAlchemy更新Postgres記錄

[英]Python SQLAlchemy Update Postgres Record

我正在嘗試使用multiprocessing模塊更新數據庫上的行(異步方式)。 我的代碼具有一個簡單的函數create_member ,該函數將一些數據插入表中,然后創建一個可能會更改此數據的過程。 問題是傳遞給async_create_member的會話正在關閉數據庫連接,下一個請購單我得到了psycopg的錯誤:

(Interface Error) connection already closed 

這是代碼:

def create_member(self, data):
    member = self.entity(**data)
    self.session.add(member)
    for name in data:
        setattr(member, name, data[name])
    self.session.commit()
    self.session.close()
    if self.index.is_indexable:
        Process(target=self.async_create_member,
            args=(data, self.session)).start()
    return member

def async_create_member(self, data, session):
    ok, data = self.index.create(data)
    if ok:

        datacopy = data.copy()
        data.clear()
        data['document'] = datacopy['document']
        data['dt_idx'] = datacopy['dt_idx']
        stmt = update(self.entity.__table__).where(
            self.entity.__table__.c.id_doc == datacopy['id_doc'])\
            .values(**data)

        session.begin()
        session.execute(stmt)
        session.commit()
        session.close()

我可以通過在async_create_member上創建一個新的連接來解決此async_create_member ,但這在postgres上留下了太多的idle事務:

engine = create_new_engine()
conn = engine.connect()
conn.execute(stmt)
conn.close()

我現在應該怎么辦? 有沒有辦法解決第一個代碼? 還是應該繼續使用create_new_engine函數創建新的連接? 我應該使用線程還是進程?

您不能跨線程或進程重用會話。 會話不是線程安全的 ,並且會話基礎的連通性不能在進程之間清晰地繼承。 您得到的錯誤消息是准確的,如果沒有提供參考:如果您在跨進程邊界繼承后嘗試使用數據庫連接,則該數據庫連接實際上已關閉。

在大多數情況下,是的,您應該在multiprocessing設置中為每個進程創建一個會話。

如果您的問題滿足以下條件:

  • 您正在為每個對象進行大量CPU密集型處理
  • 比較而言,數據庫寫操作相對輕量
  • 您想使用很多流程(我在8台以上核心計算機上執行此操作)

創建擁有會話的單個編寫器進程並將對象傳遞給該進程可能是值得的。 這是通常為我工作的方式(注意:並非意味着可以運行代碼):

import multiprocessing
from your_database_layer import create_new_session, WhateverType

work = multiprocessing.JoinableQueue()

def writer(commit_every = 50):
    global work
    session = create_new_session()
    counter = 0

    while True:
        item = work.get()
        if item is None:
            break

        session.add(item)
        counter += 1
        if counter % commit_every == 0:
            session.commit()

        work.task_done()

    # Last DB writes
    session.commit()

    # Mark the final None in the queue as complete
    work.task_done()
    return


def very_expensive_object_creation(data):
    global work
    very_expensive_object = WhateverType(**data)
    # Perform lots of computation
    work.put(very_expensive_object)
    return


def main():
    writer_process = multiprocessing.Process(target=writer)
    writer_process.start()

    # Create your pool that will feed the queue here, i.e.
    workers = multiprocessing.Pool()
    # Dispatch lots of work to very_expensive_object_creation in parallel here
    workers.map(very_expensive_object_creation, some_iterable_source_here)
    # --or-- in whatever other way floats your boat, such as
    workers.apply_async(very_expensive_object_creation, args=(some_data_1,))
    workers.apply_async(very_expensive_object_creation, args=(some_data_2,))
    # etc.

    # Signal that we won't dispatch any more work
    workers.close()

    # Wait for the creation work to be done
    workers.join()

    # Trigger the exit condition for the writer
    work.put(None)

    # Wait for the queue to be emptied
    work.join()

    return

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM