Python线程/进程和类变量

时间:2013-03-29 17:10:30

标签: python variables parallel-processing

这个问题可能真的很愚蠢,但我从今天早上开始研究这段代码,现在即使是愚蠢的事情也很难:\

我有这个代码,我通过制作8个进程并运行它来调用它。 然后还有另一个线程必须打印关于这8个进程的信息。 (代码如下)。

import MSCHAPV2
import threading
import binascii
import multiprocessing

class CrackerThread(multiprocessing.Process):

    password_header = "s."
    current_pin = ""
    username = ""
    server_challenge = ""
    peer_challenge = ""
    nt_response = ""
    starting_pin = 0
    limit = 0
    testing_pin = 0
    event = None

    def __init__(self, username, server_challenge, peer_challenge, nt_response, starting_pin, limit, event):
        #threading.Thread.__init__(self)
        super(CrackerThread, self).__init__()
        self.username = username
        self.server_challenge = server_challenge
        self.peer_challenge = peer_challenge
        self.nt_response = nt_response
        self.starting_pin = starting_pin
        self.limit = limit
        self.event = event
        self.testing_pin = starting_pin        
        #self.setDaemon(True)

    def run(self):        
        mschap = MSCHAPV2.MSCHAPV2()
        pin_range = self.starting_pin+self.limit
        while self.testing_pin <= pin_range and not self.event.isSet():
            self.current_pin = "%s%08d" % (self.password_header, self.testing_pin)                      
            if(mschap.CheckPassword(self.server_challenge, self.peer_challenge, self.username, self.current_pin.encode("utf-16-le"), self.nt_response)):
                self.event.set()
                print "Found valid password!"
                print "user     =", self.username
                print "password =", self.current_pin                
            self.testing_pin+=1            
        print "Thread for range (%d, %d) ended with no success." % (self.starting_pin, pin_range)

    def getCurrentPin(self):        
        return self.testing_pin

def printCrackingState(threads):
    info_string = '''
    ++++++++++++++++++++++++++++++++++
    + Starting password = s.%08d +
    +--------------------------------+    
    + Current pin       = s.%08d +
    ++++++++++++++++++++++++++++++++++
    + Missing pins      =   %08d +
    ++++++++++++++++++++++++++++++++++
                  '''

    while 1:        
        for t in threads:            
            printed_string = info_string % (t.starting_pin, t.getCurrentPin(), t.getMissingPinsCount())
            sys.stdout.write(printed_string)
        sys.stdout.write("--------------------------------------------------------------------")
        time.sleep(30)

printCrackingState在我的“主要”中由这些行调用:

infoThread = threading.Thread(target = utils.printCrackingState, args=([processes]))  
#infoThread = cursesTest.CursesPrinter(threads, processes, event)    
infoThread.setDaemon(True)
infoThread.start() 

现在问题是:为什么t.starting_pint.getCurrentPin()打印SAME值? 这就像t.getCurrentPin()返回__init__()方法中设置的值并且不知道我正在递增它!

建议?

1 个答案:

答案 0 :(得分:2)

您的问题是,您尝试在一个进程中更新变量,并在另一个进程中读取它。你不能这样做。与多线程相反,多处理的重点是默认情况下不共享变量。

阅读文档,尤其是Exchanging objects between processesSharing state between processes,它将解释各种方法。但实际上,有两个:要么你需要某种通道/ API让父进程询问子进程的当前状态,要么你需要某种共享内存来存储数据。你可能需要一个锁来保护通道/共享内存。

虽然共享内存在这里似乎是“显而易见”的答案,但您可能想要计算以下时间:

val = 0
for i in range(10000):
    val += 1

val = Value('i', 0)
lock = Lock()
for i in range(10000):
    with lock:
        val.value += 1

值得注意的是,你的代码在线程中也是不正确的 - 虽然它可能在CPython中有效。如果您不进行任何同步,则无法保证订购。如果您在一个线程中写入一个值并在另一个线程中“稍后”读取它,您仍然可以读取旧值。多久以后?好吧,如果线程0在核心0上运行,而线程1在核心1上运行,并且它们都在其缓存中有变量,并且没有人告诉CPU刷新缓存,则线程1将继续读取旧值。在实践中,CPython的Global Interpreter Lock最终会隐式地同步所有内容(所以我们说的是毫秒而不是无穷大),并且所有变量都有明确的内存位置,而不是被优化为寄存器,等等,所以你通常可以逃脱写无保护的比赛。但是,多亏了墨菲定律,你应该将“通常”描述为“每次直到投资者的第一个演示”或“直到我们附加活核反应堆”。