Citace "Jak mohu používat motory / připojení / relace s multiprocesingem Pythonu nebo os.fork()?" s přidaným důrazem:
Objekt SQLAlchemy Engine odkazuje na fond připojení existujících databázových připojení. Když je tedy tento objekt replikován do podřízeného procesu, cílem je zajistit, aby nebyla přenášena žádná databázová připojení .
a
V případě sdílené relace nebo připojení aktivní v transakci však neexistuje žádná automatická oprava; aplikace musí zajistit, aby nový podřízený proces pouze inicioval nové objekty připojení a transakce, stejně jako objekty relací ORM.
Problém pramení z rozvětveného podřízeného procesu, který zdědí živou globální session
, který se drží Connection
. Když target
volá init
, přepíše globální odkazy na engine
a session
, čímž se sníží jejich přepočítání na 0 v dítěti, což je přinutí dokončit. Pokud například tak či onak vytvoříte další odkaz na zděděnou relaci v dítěti, zabráníte jejímu vyčištění – ale nedělejte to. Po main
se připojila a vrací se do běžného provozu, pokouší se využít nyní potenciálně dokončené – nebo jinak nesynchronizované – připojení. Pokud jde o to, proč to způsobuje chybu pouze po určitém počtu iterací, nejsem si jistý.
Jediný způsob, jak tuto situaci zvládnout pomocí globals způsobem, který děláte vy, je
- Uzavřete všechny relace
- Zavolejte
engine.dispose()
před rozvětvením. Tím zabráníte úniku spojů k dítěti. Například:
def main():
global session
init()
try:
dummy = Dummy(value=1)
session.add(dummy)
session.commit()
dummy_id = dummy.id
# Return the Connection to the pool
session.close()
# Dispose of it!
engine.dispose()
# ...or call your cleanup() function, which does the same
p = multiprocessing.Process(target=target, args=(dummy_id,))
p.start()
p.join()
# Start a new session
session = Session()
dummy = session.query(Dummy).get(dummy_id)
assert dummy.value == 2
finally:
cleanup()
Váš druhý příklad nespouští finalizaci v potomkovi, a tak se zdá, že funguje, i když může být stejně nefunkční jako první, protože stále zdědí kopii relace a její připojení definované lokálně v main
.