Почему потоки не завершают выполнение в Python? Семафоры обеспечивают синхронизацию процессов, но выполнение не завершается

1

Предоставленный код составляет около 2 thread пытающихся получить доступ к функции increment() для увеличения значения global variable x. Я разработал semaphore class для синхронизации процессов. Таким образом, ожидаемое приращение каждого потока ожидается в 2000000 1000000 сумм до 2000000. Но фактическая производительность не достигает 2000000. Выход достигает 1800000 - 1950000. Почему все циклы не выполняются?

import threading as th

x=0

class Semaphore:
    def __init__(self):
        self.__s = 1
    def wait(self):
        while(self.__s==0):
            pass
        self.__s-=1

    def signal(self):
        self.__s+=1

def increament(s):
    global x
    s.wait()
    x+=1
    s.signal()

def task1(s):
    for _ in range(1000000):
        increament(s)

def task2(s):
    for _ in range(1000000):
        increament(s)

def main():
    s = Semaphore()
    t1 = th.Thread(target=task1,name="t1",args=(s,))
    t2 = th.Thread(target=task2,name="t1",args=(s,))
    t1.start()
    t2.start()
    #Checking Synchronization
    for _ in range(10):
        print("Value of X: %d"%x)

    #waiting for termination of thread
    t2.join()
    t1.join()


if __name__=="__main__":
    main()
    print("X = %d"%x) #Final Output

Выход:

Value of X: 5939
Value of X: 14150
Value of X: 25036
Value of X: 50490
Value of X: 54136
Value of X: 57674
Value of X: 69994
Value of X: 84912
Value of X: 94284
Value of X: 105895
X = 1801436
Теги:
multithreading
semaphore
process
thread-synchronization

1 ответ

0

Нити работают нормально, и они завершатся правильно. Это ваша переменная "z", что проблема.

В общем случае использование глобальной переменной в качестве контейнера для вашей общей памяти между двумя потоками - это плохой способ.

Проверьте этот ответ, чтобы понять, почему.

Я внесла следующие изменения в ваш код. Я сделал "z" общую переменную, а "x" и "y" - данные для каждого потока.

x=0
y=0
z=0

def increament1(s):
    global x,z
    s.wait()
    x+=1
    z+=1
    s.signal()

def increament2(s):
    global y,z
    s.wait()
    y+=1
    z+=1
    s.signal()

def task1(s):
    for somei in range(1000000):
        increament1(s)

def task2(s):
    for somej in range(1000000):
        increament2(s)

Это результат, который я получил:

X = 1000000
Y = 1000000
Z = 1961404

Как видите, в самих потоках нет ничего плохого, так как они завершают свое исполнение. Но общие данные Z немного неловкие. Z будет изменяться случайным образом каждый раз, когда вы запускаете скрипт. Следовательно, как вы можете видеть, используя глобальные переменные, поскольку разделяемая память - плохая идея.

Гораздо лучшим вариантом будет использование некоторых поддерживаемых python инструментов обмена, таких как Queue, предоставляемых самой библиотекой python. Это многопроцессорная многопользовательская очередь сообщений и помогает, когда речь идет об общих данных, таких как данные, которые вы используете сейчас.

Позвольте мне показать вам, как это можно сделать с помощью Queue:

import threading as th
from Queue import Queue

def task1(q):
    global x,z
    for somei in range(1000000):
        q.put(q.get() + 1)

def task2(q):
    global y,z
    for somei in range(1000000):
        q.put(q.get() + 1)

def main():
    queue = Queue()
    queue.put(0)
    t1 = th.Thread(target=task1,name="t1",args=(queue, ))
    t2 = th.Thread(target=task2,name="t1",args=(queue, ))
    t1.start()
    t2.start()
    #Checking Synchronization

    t1.join()
    t2.join()
    return queue.get()

if __name__=="__main__":
    print("Queue = %d"%main()) #Final Output

Вам даже не нужно создавать семафор здесь, так как очередь будет автоматически следить за синхронизацией.

Результатом этой окончательной программы является:

Queue = 2000000

Ещё вопросы

Сообщество Overcoder
Наверх
Меню