web-dev-qa-db-fra.com

Utilisation correcte des mutex dans Python

Je commence par des multi-threads dans python (ou du moins, il est possible que mon script crée plusieurs threads). Cet algorithme serait-il l'utilisation appropriée d'un mutex? Je n'ai pas testé ce code encore et cela ne fonctionnera probablement même pas.Je veux juste que processData soit exécuté dans un thread (un à la fois) et que la boucle while continue à fonctionner, même s’il ya un thread dans la file d’attente.

from threading import Thread
from win32event import CreateMutex
mutex = CreateMutex(None, False, "My Crazy Mutex")
while(1)
    t = Thread(target=self.processData, args=(some_data,))
    t.start()
    mutex.lock()

def processData(self, data)
    while(1)
        if mutex.test() == False:
            do some stuff
            break

Edit: relisant mon code, je peux voir qu'il est totalement faux. mais bon, c'est pourquoi je suis ici pour demander de l'aide.

64
Richard

Je ne sais pas pourquoi vous utilisez le mutex de Window au lieu de celui de Python. En utilisant les méthodes Python, c'est assez simple:

from threading import Thread, Lock

mutex = Lock()

def processData(data):
    mutex.acquire()
    try:
        print('Do some stuff')
    finally:
        mutex.release()

while True:
    t = Thread(target = processData, args = (some_data,))
    t.start()

Notez toutefois qu'en raison de l'architecture de CPython (à savoir Global Interpreter Lock ), vous n'aurez de toute façon qu'un seul thread à la fois, ce qui est bien si plusieurs d'entre eux sont des E/S. lié, bien que vous souhaitiez libérer le verrou autant que possible pour que le thread lié aux E/S ne bloque pas l'exécution des autres threads.

Une alternative, pour Python 2.6 et versions ultérieures, consiste à utiliser le package multiprocessing de Python. Elle reflète le package threading, mais créera des processus entièrement nouveaux qui peut s'exécuter simultanément. Il est simple de mettre à jour votre exemple:

from multiprocessing import Process, Lock

mutex = Lock()

def processData(data):
    with mutex:
        print('Do some stuff')

if __== '__main__':
    while True:
        p = Process(target = processData, args = (some_data,))
        p.start()
138
Chris B.

Voici la solution que j'ai trouvée:

import time
from threading import Thread
from threading import Lock

def myfunc(i, mutex):
    mutex.acquire(1)
    time.sleep(1)
    print "Thread: %d" %i
    mutex.release()


mutex = Lock()
for i in range(0,10):
    t = Thread(target=myfunc, args=(i,mutex))
    t.start()
    print "main loop %d" %i

Sortie:

main loop 0
main loop 1
main loop 2
main loop 3
main loop 4
main loop 5
main loop 6
main loop 7
main loop 8
main loop 9
Thread: 0
Thread: 1
Thread: 2
Thread: 3
Thread: 4
Thread: 5
Thread: 6
Thread: 7
Thread: 8
Thread: 9
13
Richard

Vous devez déverrouiller votre Mutex à un moment donné ...

8

Je voudrais améliorer réponse de chris-b un peu plus.

Voir ci-dessous pour mon code:

from threading import Thread, Lock
import threading
mutex = Lock()


def processData(data, thread_safe):
    if thread_safe:
        mutex.acquire()
    try:
        thread_id = threading.get_ident()
        print('\nProcessing data:', data, "ThreadId:", thread_id)
    finally:
        if thread_safe:
            mutex.release()


counter = 0
max_run = 100
thread_safe = False
while True:
    some_data = counter        
    t = Thread(target=processData, args=(some_data, thread_safe))
    t.start()
    counter = counter + 1
    if counter >= max_run:
        break

Dans votre première manche si vous définissez thread_safe = False dans la boucle while, le mutex ne sera pas utilisé et les threads se superposeront dans la méthode print comme ci-dessous;

Not Thread safe

mais si vous définissez thread_safe = True et lancez-le, vous verrez que le résultat est parfait.

Thread safe

j'espère que cela t'aides.

5
Teoman shipahi