Multythread et Queue en Python

1 réponse
Avatar
Stephane Tougard
Bonjour,

J'ai un programme multi-threadé en Python qui parle avec une base
Postgres. Pour éviter les problèmes d'accès concurrentiels avec la base,
je crée un thread qui va recevoir les requêtes des autres threads via
queue.get et queue.put (il ne fait que des insert, donc je n'ai pas
besoin de vérifier la valeur de retour de la requete).

Mon problème est que si je limite à 10 threads, no problems, tout
fonctionne.

Mais si je monte à 100 threads, le programme se bloque (visiblement sur
lock_acquire()).

Tous les put() et get() sont avec True et un timeout de 5 secondes.

Avant de rentrer dans le détail du code, y-a-t-il quelque chose
d'évident que je ne sais pas ? genre faire 100 threads avec Python, je
suis en pleine science fiction ou le global lock est incapable de gérer
plus de 15 threads correctement ?

La fonction du thread qui gère les requetes SQL

def execute_sql(q):
print("Start SQL Thread")
while True:
try:
data = q.get(True,5)
except:
print("No data")
continue

print("RECEIVED SQL ORDER")
print(data)
print("END")
if data == "EXIT":
return
try:
request = data['request']
arg = data['arg']
ref.execute(request,arg)
except:
print("Can not execute SQL request")
print(data)


L'appel de ce thread depuis un autre thread

sql = dict()
sql['request'] = "update b2_user set credit = credit -%s where id = %s"
sql['arg'] = (i,username,)
try:
q.put(sql,True,5)
except:
print("Can not insert data")

Et le lancement du thread SQL

q = qu.Queue()
t = th.Thread(target = execute_sql, args = (q,))
t.start()

1 réponse

Avatar
Artis Sideley
On Thursday, 14 May 2020 11:24:26 UTC+2, Stephane Tougard wrote:
Bonjour,
J'ai un programme multi-threadé en Python qui parle avec une base
Postgres. Pour éviter les problèmes d'accès concurrentiels avec la base,
je crée un thread qui va recevoir les requêtes des autres threa ds via
queue.get et queue.put (il ne fait que des insert, donc je n'ai pas
besoin de vérifier la valeur de retour de la requete).
Mon problème est que si je limite à 10 threads, no problems, to ut
fonctionne.
Mais si je monte à 100 threads, le programme se bloque (visiblement sur
lock_acquire()).
Tous les put() et get() sont avec True et un timeout de 5 secondes.
Avant de rentrer dans le détail du code, y-a-t-il quelque chose
d'évident que je ne sais pas ? genre faire 100 threads avec Python, je
suis en pleine science fiction ou le global lock est incapable de gé rer
plus de 15 threads correctement ?
La fonction du thread qui gère les requetes SQL
def execute_sql(q):
print("Start SQL Thread")
while True:
try:
data = q.get(True,5)
except:
print("No data")
continue
print("RECEIVED SQL ORDER")
print(data)
print("END")
if data == "EXIT":
return
try:
request = data['request']
arg = data['arg']
ref.execute(request,arg)
except:
print("Can not execute SQL request")
print(data)
L'appel de ce thread depuis un autre thread
sql = dict()
sql['request'] = "update b2_user set credit = credit -%s where id = %s"
sql['arg'] = (i,username,)
try:
q.put(sql,True,5)
except:
print("Can not insert data")
Et le lancement du thread SQL
q = qu.Queue()
t = th.Thread(target = execute_sql, args = (q,))
t.start()

Normalement, les SGBD ont intrinsèquement des mécanismes de prote ction contre les pb d'accès concurrents. Mais si vous avez besoin d'or donner les requetes, programmer les requetes séquentiellement dans un unique thread.
Le multi thread est consommateur de ressources mémoire. Dans votre cas , s'il ne s'agit d'émettre les requetes et recevoir les résultats , essayer la bibliothèque 'asyncio' beaucoup plus économe en ress ources.