sql >> Database >  >> RDS >> PostgreSQL

Django ORM lekt verbindingen bij gebruik van ThreadPoolExecutor

Mijn gok is dat de ThreadPoolExecutor is niet wat de DB-verbinding tot stand brengt, maar de ingepaste banen zijn degenen die de verbinding houden. Ik heb hier al mee te maken gehad.

Uiteindelijk heb ik deze wrapper gebouwd om ervoor te zorgen dat threads handmatig worden gesloten wanneer taken worden uitgevoerd in een ThreadPoolExecutor. Dit zou handig moeten zijn om ervoor te zorgen dat verbindingen niet worden gelekt, tot nu toe heb ik geen lekken gezien tijdens het gebruik van deze code.

from functools import wraps
from concurrent.futures import ThreadPoolExecutor
from django.db import connection

class DjangoConnectionThreadPoolExecutor(ThreadPoolExecutor):
    """
    When a function is passed into the ThreadPoolExecutor via either submit() or map(), 
    this will wrap the function, and make sure that close_django_db_connection() is called 
    inside the thread when it's finished so Django doesn't leak DB connections.

    Since map() calls submit(), only submit() needs to be overwritten.
    """
    def close_django_db_connection(self):
        connection.close()

    def generate_thread_closing_wrapper(self, fn):
        @wraps(fn)
        def new_func(*args, **kwargs):
            try:
                return fn(*args, **kwargs)
            finally:
                self.close_django_db_connection()
        return new_func

    def submit(*args, **kwargs):
        """
        I took the args filtering/unpacking logic from 
   
        https://github.com/python/cpython/blob/3.7/Lib/concurrent/futures/thread.py 
        
        so I can properly get the function object the same way it was done there.
        """
        if len(args) >= 2:
            self, fn, *args = args
            fn = self.generate_thread_closing_wrapper(fn=fn)
        elif not args:
            raise TypeError("descriptor 'submit' of 'ThreadPoolExecutor' object "
                        "needs an argument")
        elif 'fn' in kwargs:
            fn = self.generate_thread_closing_wrapper(fn=kwargs.pop('fn'))
            self, *args = args
    
        return super(self.__class__, self).submit(fn, *args, **kwargs)

Dan kun je dit gewoon gebruiken:

    with DjangoConnectionThreadPoolExecutor(max_workers=15) as executor:
        results = list(executor.map(func, args_list))

...en er zeker van zijn dat de verbindingen zullen sluiten.




  1. Hoe exporteer ik gegevens van SQL Server 2008.2010 in DML (SQL-script)?

  2. 12 veelgebruikte SQL-operators

  3. Geeft TSQL snellere resultaten dan de opgeslagen procedure in SQL Server?

  4. Tips en trucs van Postgres