IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

[Python 2.7, Sqlite, Multithreading trop rapide ?


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Développeur Full Stack
    Inscrit en
    Janvier 2007
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Janvier 2007
    Messages : 30
    Points : 19
    Points
    19
    Par défaut [Python 2.7, Sqlite, Multithreading trop rapide ?
    Bonjour à tous,

    J'ai besoin de faire une multitude de requètes, rapidement, avec Python / Sqlite.
    J'aurais donc besoin du multithreading.

    J'ai créé une classe héritant de Thread, avec une méthode qui sélectionne un enregistrement dans la base de données, et qui update un champ 'working=1'.
    Ensuite, je me sers de cet enregistrement pour d'autres opération.

    Donc : Le problème est que, le temps que je fasse le select et que je le mettes à jour, le 2e thread a déjà sélectionné le même enregistrement.

    Ainsi, par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    class testeurThread(Thread):
     
        def __init__(self, task):
            Thread.__init__(self)
            self.task = task
     
        def run(self):
    		if self.task == 1:
    			self.testThread1()
    		else:
    			self.testThread2()
     
    	def execute(self):
    		self.database = sqlite3.connect(config.__DBNAME__)
            self.cursor = self.database.cursor()
            self.cursor.execute(query)        
            self.cursor.close()
     
    	def testThread1():
            data = self.fetchall('SELECT * FROM test WHERE working = 0 LIMIT 1')
     
            for row in data:
    			self.lockSite(test_id, 0)        
    			## working
    			self.lockSite(test_id, 1)        
    	def testThread2():
     
    (...)
     
     
     
    thread_1 = Crawler(1)
    thread_2 = Crawler(1)
     
    thread_1.start()
    thread_2.start()
     
    thread_1.join()
    thread_2.join()
    Autre problème rencontré : Je suis obligé, dans la méthode 'execute', j'ouvrir, utiliser et fermer la base de données, sinon il semble se mélanger les pinceaux entre les différents threads...

    J'aurais trois petites questions subsidiaires, sachant que je commence en Python / Sqlite / Multithread
    1/ Ma façon de faire est-elle bonne, à savoir : mettre tout le code dans la classe qui hérite de Thread ?
    ( sachant que dans les exemples que l'on voit sur le net, le code est toujours réduit au minimum, à croire qu'il faille en mettre le moins possible..)

    2/ Chaque méthode a comme paramètre 'self'. Ca vous semble normal ?

    3/ Au sujet des 'import' que l'on case en début de fichier : Je me retrouve, pour mon code, avec une quinzaine de fichiers à 'importer'. Ca vous semble normal ? Y a t-il une autre facon de faire ?

    Merci d'avance !

  2. #2
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Salut,

    SQLite n'est pas thread-safe par default. Je sais pas comment Python gere ca. Il faut que tu verifies:
    • SQLite soit compile pour le multi-thread
    • Que tu passes le bon flag a connect() pour passer en mode multithread
    • Que tu ais une connexion par thread a la base (ca c'est OK dans ton cas)

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par Anonymus Voir le message
    J'ai besoin de faire une multitude de requètes, rapidement, avec Python / Sqlite.
    J'aurais donc besoin du multithreading.
    Un CPU sera toujours 1000 fois plus rapide que les lectures/écritures disques sauf à les répartir sur plein de disques SSD via des "stripe set".
    Par ailleurs, la plupart des SGDB tendent à sérialiser tout ou partie du traitement des requêtes car il faut bien assurer l'intégrité de la base de donnée.
    Voir la FAQ de SQLite:
    (6) Is SQLite threadsafe?

    Threads are evil. Avoid them.

    SQLite is threadsafe. We make this concession since many users choose to ignore the advice given in the previous paragraph. But in order to be thread-safe, SQLite must be compiled with the SQLITE_THREADSAFE preprocessor macro set to 1. Both the Windows and Linux precompiled binaries in the distribution are compiled this way. If you are unsure if the SQLite library you are linking against is compiled to be threadsafe you can call the sqlite3_threadsafe() interface to find out.

    SQLite is threadsafe because it uses mutexes to serialize access to common data structures. However, the work of acquiring and releasing these mutexes will slow SQLite down slightly. Hence, if you do not need SQLite to be threadsafe, you should disable the mutexes for maximum performance. See the threading mode documentation for additional information.

    Under Unix, you should not carry an open SQLite database across a fork() system call into the child process.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre à l'essai
    Profil pro
    Développeur Full Stack
    Inscrit en
    Janvier 2007
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Janvier 2007
    Messages : 30
    Points : 19
    Points
    19
    Par défaut
    Merci pour vos réponses,
    J'ai donc modifié mon script pour placer les requètes sql avant la fonction principale (qui consiste à récupérer des flux/pages).

    Je me retrouve devant un autre problème, à savoir : Je n'arrive pas à savoir quand les threads sont terminés. Dans le code ci-dessous, je ne sais pas où placer le .join, qui me permettrait de reboucler sur les threads.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    NB_THREADS = 10
     
    for compteur in range(10):
     
        database = sqlite3.connect(config.__DBNAME__)
        cursor = database.cursor()
        cursor.execute('SELECT flux_id, url FROM flux WHERE error = 0 ORDER BY flux_id ASC limit 0,?', (NB_THREADS,))
        data = cursor.fetchall()
        database.commit()
        cursor.close()
     
        for i in range(NB_THREADS):
            try:
                flux_id = data[i][0]
                url = data[i][1]
     
                threads = []
                t = threading.Thread(target=getContent, args=(flux_id, url, ))
                threads.append(t)
                t.start()
     
            except Exception as ex:
                sys.stdout.write('\n')
                sys.stdout.write('>> ' + str(flux_id) + ' :::: ' + str(ex))
                sys.stdout.flush()

    Merci d'avance,

  5. #5
    Membre à l'essai
    Profil pro
    Développeur Full Stack
    Inscrit en
    Janvier 2007
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Janvier 2007
    Messages : 30
    Points : 19
    Points
    19
    Par défaut
    Trouvé !

    Dans la boucle, il suffit de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        for t in threads:
            t.join()
    Merci à tous,

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Déplacements trop rapides
    Par Exedor dans le forum Ogre
    Réponses: 8
    Dernier message: 09/08/2006, 08h43
  2. Traitement trop rapide
    Par Ludog35 dans le forum Access
    Réponses: 2
    Dernier message: 19/06/2006, 14h25
  3. [VBA-E] Liaisons qui ne se mettent pas à jour (macro trop rapide?)
    Par minikisskool dans le forum Macros et VBA Excel
    Réponses: 16
    Dernier message: 21/11/2005, 09h36
  4. Horloge 2x trop rapide!
    Par rgy834 dans le forum Administration système
    Réponses: 6
    Dernier message: 24/10/2005, 21h08
  5. Compte à rebours trop rapide
    Par Anduriel dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 12/06/2005, 20h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo