这个问题可能真的很愚蠢,但我从今天早上开始研究这段代码,现在即使是愚蠢的事情也很难:\
我有这个代码,我通过制作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_pin
和t.getCurrentPin()
打印SAME值?
这就像t.getCurrentPin()
返回__init__()
方法中设置的值并且不知道我正在递增它!
建议?
答案 0 :(得分:2)
您的问题是,您尝试在一个进程中更新变量,并在另一个进程中读取它。你不能这样做。与多线程相反,多处理的重点是默认情况下不共享变量。
阅读文档,尤其是Exchanging objects between processes和Sharing 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最终会隐式地同步所有内容(所以我们说的是毫秒而不是无穷大),并且所有变量都有明确的内存位置,而不是被优化为寄存器,等等,所以你通常可以逃脱写无保护的比赛。但是,多亏了墨菲定律,你应该将“通常”描述为“每次直到投资者的第一个演示”或“直到我们附加活核反应堆”。