Правильное использование мьютексов в Python - PullRequest
63 голосов
/ 22 июля 2010

Я начинаю с многопоточности в python (или, по крайней мере, возможно, что мой скрипт создает несколько потоков).этот алгоритм будет правильным использованием Mutex?Я еще не тестировал этот код, и он, вероятно, даже не будет работать.Я просто хочу, чтобы processData запускался в потоке (по одному), а основной цикл while продолжался, даже если в очереди есть поток.

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

Редактировать: перечитывая мой код, я вижу, что это совершенно неправильно.но эй, вот почему я здесь прошу помощи.

Ответы [ 4 ]

133 голосов
/ 22 июля 2010

Я не знаю, почему вы используете мьютекс Window вместо Python. Используя методы Python, это довольно просто:

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()

Но обратите внимание, что из-за архитектуры CPython (а именно, Global Interpreter Lock ) у вас все равно будет эффективно работать только один поток за раз - это нормально, если их число / O привязан, хотя вы захотите снять блокировку настолько, насколько это возможно, чтобы поток, связанный с вводом / выводом, не блокировал выполнение других потоков.

Альтернативой для Python 2.6 и новее является использование пакета multiprocessing Python. Он отражает пакет threading, но создаст совершенно новые процессы, которые могут выполняться одновременно. Обновление вашего примера тривиально:

from multiprocessing import Process, Lock

mutex = Lock()

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

if __name__ == '__main__':
    while True:
        p = Process(target = processData, args = (some_data,))
        p.start()
13 голосов
/ 22 июля 2010

Вот решение, которое я придумал:

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

Выход:

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
8 голосов
/ 22 июля 2010

Вы должны разблокировать свой Mutex когда-нибудь ...

5 голосов
/ 23 марта 2018

Я хотел бы улучшить ответ с chris-b немного больше.

Смотрите мой код ниже:

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

При первом запуске, если вы установили thread_safe = False в цикле while, мьютекс не будет использоваться, и потоки будут перешагивать друг друга в методе печати, как показано ниже;

Not Thread safe

но, если вы установите thread_safe = True и запустите его, вы увидите, что все результаты выдаются идеально;

Thread safe

надеюсь, это поможет.

...