在返回之前,后续代码正在更新要返回的同步值

时间:2014-04-18 09:53:08

标签: python multithreading synchronization locking

我编写了下面的代码来处理和收集性能计数器(包括测试行(代码末尾))。

但是,当我调用函数getAndReset()时,它似乎在输出lendingStats字典的当前值之前将值重置为零。尽管在函数getAndReset()中,lendingStats值先被更新,然后存储在变量theStats中。

#!/usr/bin/python

import threading
import time, datetime,pytz

startTime = datetime.datetime.now(pytz.timezone('Africa/Nairobi')).strftime('%Y-%m-%d %H:%M:%S%z')

lendingStats = {'ussdRequests':{'getSubInfo':None,'loanRequests':None},'time':{'startTime':startTime,'currentTime':startTime,'last-reset-time:':startTime}}
lendingStatsNow = {'ussdRequests':{'getSubInfo':None,'loanRequests':None},'time':{'startTime':startTime,'currentTime':startTime,'last-reset-time:':startTime}}
subInfoCounter = dict()
loanRequestCounter = dict()
currentTime = startTime
lastResetTime = startTime

def synchronized(func): 
    func.__lock__ = threading.RLock()
    def synced_func(*args, **kws):
        with func.__lock__:
            return func(*args, **kws)
    return synced_func

@synchronized
def lastResetTimeFunc(action):  
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    if action == "Get":
        return lastResetTime
    elif action == "Update":
        lastResetTime = datetime.datetime.now(pytz.timezone('Africa/Nairobi')).strftime('%Y-%m-%d %H:%M:%S%z')      

#@synchronized  
def getAndReset():  
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    # Get the values to return
    theStats = dict()
    theStats = getLendingStats()        
    resetStats()
    return theStats 

@synchronized   
def resetStats():
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    ussdSubInfoStatsFunc(action="Reset")
    ussdLoanReqStatsFunc(action="Reset")
    lastResetTimeFunc("Update")

@synchronized
def getLendingStats():
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    # Get the values
    # lendingStats['ussdRequests']['getSubInfo'] = ussdSubInfoStatsFunc(action="Get")       
    # lendingStats['ussdRequests']['loanRequests'] = ussdLoanReqStatsFunc(action="Get")
    # lendingStats['time']['last-reset-time'] = lastResetTimeFunc("Get")
    # lendingStats['time']['currentTime'] = getCurrentTimeFunc()
    returnValue = dict()
    for KeyName in lendingStats.iterkeys():
        returnValue[KeyName] = dict()
    returnValue['ussdRequests']['getSubInfo'] = ussdSubInfoStatsFunc(action="Get")      
    returnValue['ussdRequests']['loanRequests'] = ussdLoanReqStatsFunc(action="Get")
    returnValue['time']['last-reset-time'] = lastResetTimeFunc("Get")
    returnValue['time']['currentTime'] = getCurrentTimeFunc()
    returnValue['time']['startTime'] = lendingStats['time']['startTime']

    lendingStats = returnValue
    # Return the Values
    return returnValue


@synchronized
def getCurrentTimeFunc():
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    currentTime = datetime.datetime.now(pytz.timezone('Africa/Nairobi')).strftime('%Y-%m-%d %H:%M:%S%z')
    theTime = currentTime
    return theTime

@synchronized
def ussdLoanReqStatsFunc(**kwargs):
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    if kwargs['action'] == "Add":
        if loanRequestCounter.has_key(kwargs['respcode']):
            if loanRequestCounter[kwargs['respcode']].has_key(kwargs['denom']):
                currentcount = loanRequestCounter[kwargs['respcode']][kwargs['denom']]
                loanRequestCounter[kwargs['respcode']][kwargs['denom']] = currentcount + 1  
            else:
                loanRequestCounter[kwargs['respcode']][kwargs['denom']] = 1
        else:
            loanRequestCounter[kwargs['respcode']] = dict()
            loanRequestCounter[kwargs['respcode']][kwargs['denom']] = 1
    elif kwargs['action'] == "Reset":
        for respCodeKeyName in loanRequestCounter.iterkeys():
            for denomKeyName in loanRequestCounter[respCodeKeyName].iterkeys():
                loanRequestCounter[respCodeKeyName][denomKeyName] = 0
    elif kwargs['action'] == "Get":
        theDict = loanRequestCounter
        return theDict

@synchronized
def ussdSubInfoStatsFunc(**kwargs):
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    if kwargs['action'] == "Add":
        if subInfoCounter.has_key(kwargs['respcode']):
            currentcount = subInfoCounter[kwargs['respcode']]
            subInfoCounter[kwargs['respcode']] = currentcount + 1           
        else:
            subInfoCounter[kwargs['respcode']] = 1
    elif kwargs['action'] == "Reset":
        for keyname in subInfoCounter.iterkeys():
            subInfoCounter[keyname] = 0
    elif kwargs['action'] == "Get":
        theDict = subInfoCounter
        return theDict

def testSubInfoCounter(KeyName,numOfEvents):
    i = 0
    while i < numOfEvents:
        ussdSubInfoStatsFunc(action="Add",respcode=KeyName)
        i +=1
    print ussdSubInfoStatsFunc(action="Get")

def testLoanReqCounter(respCodeT,theDenom,numOfEvents):
    i = 0
    while i < numOfEvents:
        ussdLoanReqStatsFunc(action="Add",respcode=respCodeT,denom=theDenom)
        i +=1
    print ussdLoanReqStatsFunc(action="Get")


thread1 = threading.Thread(target = testLoanReqCounter("0","200",7767))
thread2 = threading.Thread(target = testLoanReqCounter("1","1000",55))  

thread1.start()
thread2.start()

thread1.join()
thread2.join()


print "At the beginning:"
print getLendingStats()
print getAndReset()

testSubInfoCounter("9",7)

testSubInfoCounter("0",7000)

testLoanReqCounter("0","200",7767)
testLoanReqCounter("1","200",33)
testLoanReqCounter("0","1000",3928)
testLoanReqCounter("1","1000",55)
testLoanReqCounter("0","5000",492)

testSubInfoCounter("1",3000)
testSubInfoCounter("3",1000)
testSubInfoCounter("0",7000)

print "Cumulatively:"
print getAndReset()
# print getLendingStats()
# resetStats()
time.sleep(3)
print "After the Reset"
# print getLendingStats()
# resetStats()
print getAndReset()

testLoanReqCounter("0","200",7767)
testLoanReqCounter("1","200",33)
testLoanReqCounter("0","1000",3928)
testLoanReqCounter("1","1000",55)
testLoanReqCounter("0","5000",492)    

print getLendingStats()
resetStats()

testSubInfoCounter("1",3230)
testSubInfoCounter("3",1901)
testSubInfoCounter("0",76887)

print getAndReset()
time.sleep(4)
print getAndReset()
# print getLendingStats()
# resetStats()

1 个答案:

答案 0 :(得分:0)

这里的问题是我需要使用deepcopy而不是简单的赋值(使用简单的副本)。

因此,我需要更改的代码是:

import copy

@synchronized  
def getAndReset():  
    global lendingStats,subInfoCounter,loanRequestCounter,currentTime,lastResetTime
    # Get the values to return
    theStats = copy.deepcopy(getLendingStats())
    resetStats()
    return theStats