Предоставленный код составляет около 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
Нити работают нормально, и они завершатся правильно. Это ваша переменная "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