Python3中的多处理

Python3中的多处理,python,multithreading,python-3.x,multiprocessing,cracking,Python,Multithreading,Python 3.x,Multiprocessing,Cracking,我当时正在摆弄一个zip文件破解程序,并决定使用多处理模块来加速这个过程。因为这是我第一次使用这个模块,我还没有完全理解它,所以这完全是一种痛苦。然而,我让它工作了 问题是它没有完成单词列表;它只是在单词列表中随机停止,如果找到密码,它将继续遍历单词列表,而不是停止进程 有人知道它为什么表现出这种行为吗 ZipFile Cracker的源代码 #!/usr/bin/env python3 import multiprocessing as mp import zipfile # Handeli

我当时正在摆弄一个zip文件破解程序,并决定使用多处理模块来加速这个过程。因为这是我第一次使用这个模块,我还没有完全理解它,所以这完全是一种痛苦。然而,我让它工作了

问题是它没有完成单词列表;它只是在单词列表中随机停止,如果找到密码,它将继续遍历单词列表,而不是停止进程

有人知道它为什么表现出这种行为吗

ZipFile Cracker的源代码

#!/usr/bin/env python3

import multiprocessing as mp
import zipfile # Handeling the zipfile
import sys # Command line arguments, and quiting application
import time # To calculate runtime

def usage(program_name):
    print("Usage: {0} <path to zipfile> <dictionary>".format(program_name))
    sys.exit(1)

def cracker(password):
    try:
        zFile.extractall(pwd=password)
        print("[+] Password Found! : {0}".format(password.decode('utf-8')))
        pool.close()
    except:
        pass

def main():
    global zFile
    global pool

    if len(sys.argv) < 3:
        usage(sys.argv[0])

    zFile = zipfile.ZipFile(sys.argv[1])

    print("[*] Started Cracking")

    startime = time.time()
    pool = mp.Pool()

    for i in open(sys.argv[2], 'r', errors='ignore'):
        pswd = bytes(i.strip('\n'), 'utf-8')
        pool.apply_async(cracker, (pswd,))

    print (pswd)
    runtime =  round(time.time() - startime, 5)
    print ("[*] Runtime:", runtime, 'seconds')
    sys.exit(0)

if __name__ == "__main__":
    main()
#/usr/bin/env蟒蛇3
将多处理作为mp导入
导入zipfile#处理zipfile
导入sys#命令行参数并退出应用程序
导入时间#计算运行时间
def使用(程序名称):
打印(“用法:{0}”。格式(程序名))
系统出口(1)
def破解程序(密码):
尝试:
zFile.extractall(pwd=密码)
打印(“[+]找到密码!:{0}”。格式(Password.decode('utf-8'))
pool.close()
除:
通过
def main():
全局zFile
全球池
如果len(sys.argv)<3:
用法(sys.argv[0])
zFile=zipfile.zipfile(sys.argv[1])
打印(“[*]开始开裂”)
startime=time.time()
pool=mp.pool()
对于打开的i(sys.argv[2],'r',errors='ignore'):
pswd=字节(i.strip('\n'),'utf-8')
pool.apply_async(cracker,(pswd,))
打印(pswd)
runtime=round(time.time()-startime,5)
打印(“[*]运行时:”,运行时,“秒”)
系统出口(0)
如果名称=“\uuuuu main\uuuuuuuu”:
main()

您过早终止程序。要测试这一点,请在
cracker
方法中添加无害的
time.sleep(10)
,并观察程序在一秒钟内仍将终止

调用以等待池完成:

pool = mp.Pool()
for i in open(sys.argv[2], 'r', errors='ignore'):
    pswd = bytes(i.strip('\n'), 'utf-8')
    pool.apply_async(cracker, (pswd,))

pool.close()  # Indicate that no more data is coming
pool.join()   # Wait for pool to finish processing

runtime =  round(time.time() - startime, 5)
print ("[*] Runtime:", runtime, 'seconds')
sys.exit(0)
此外,一旦找到正确的密码,调用
close
仅表示未来不再有任务出现-所有已提交的任务仍将完成。相反,在不处理任何其他任务的情况下调用以终止池

此外,根据
multiprocessing.Pool
的实现细节,全局变量
Pool
在需要时可能不可用(其值无论如何都不可序列化)。要解决此问题,可以使用回调,如中所示

def cracker(password):
    try:
        zFile.extractall(pwd=password)
    except RuntimeError:
        return
    return password

 def callback(found):
     if found:
         pool.terminate()
 ...
 pool.apply_async(cracker, (pswd,), callback=cb)
当然,由于您现在一直在查看结果,
apply
不是正确的方法。相反,您可以使用以下方法编写代码:


除了使用globals,您还可能希望在每个进程中通过为池使用一个函数来打开zip文件(并创建一个
ZipFile
对象)。甚至更好(更快),首先放弃所有I/O,只读取一次所需的字节,然后将它们传递给孩子们。

phihag的答案是正确的解决方案

我只是想提供一个关于在找到正确密码后调用
terminate()
的额外细节。运行代码时,
cracker()
中的
pool
变量未定义。因此,试图从那里调用它只会引发一个异常:

NameError: name 'pool' is not defined
(我的
fork()
经验不足,所以我不完全理解为什么全局
zFile
被成功复制到子进程,而
pool
却没有。即使它被复制,它在父进程中也不会是相同的
pool
,对吗?因此对它调用的任何方法都不会对pare中的真实池产生影响nt进程。无论如何,我更喜欢
多处理
模块的编程指南部分中列出的建议:显式地将资源传递给子进程

我的建议是让
cracker()
返回正确的密码,否则返回
None
。然后将回调传递给记录正确密码的
apply_async()
,并终止池。以下是我对修改代码以实现此目的的看法:

#!/usr/bin/env python3

import multiprocessing as mp
import zipfile # Handeling the zipfile
import sys # Command line arguments, and quiting application
import time # To calculate runtime
import os

def usage(program_name):
    print("Usage: {0} <path to zipfile> <dictionary>".format(program_name))
    sys.exit(1)

def cracker(zip_file_path, password):
    print('[*] Starting new cracker (pid={0}, password="{1}")'.format(os.getpid(), password))

    try:
        time.sleep(1) # XXX: to simulate the task taking a bit of time
        with zipfile.ZipFile(zip_file_path) as zFile:
            zFile.extractall(pwd=bytes(password, 'utf-8'))
        return password
    except:
        return None

def main():
    if len(sys.argv) < 3:
        usage(sys.argv[0])

    print('[*] Starting main (pid={0})'.format(os.getpid()))

    zip_file_path = sys.argv[1]
    password_file_path = sys.argv[2]
    startime = time.time()
    actual_password = None

    with mp.Pool() as pool:
        def set_actual_password(password):
            nonlocal actual_password
            if password:
                print('[*] Found password; stopping future tasks')
                pool.terminate()
                actual_password = password

        with open(password_file_path, 'r', errors='ignore') as password_file:
            for pswd in password_file:
                pswd = pswd.strip('\n')
                pool.apply_async(cracker, (zip_file_path, pswd,), callback=set_actual_password)

        pool.close()
        pool.join()

    if actual_password:
        print('[*] Cracked password: "{0}"'.format(actual_password))
    else:
        print('[*] Unable to crack password')
    runtime =  round(time.time() - startime, 5)
    print("[*] Runtime:", runtime, 'seconds')
    sys.exit(0)

if __name__ == "__main__":
    main()
#/usr/bin/env蟒蛇3
将多处理作为mp导入
导入zipfile#处理zipfile
导入sys#命令行参数并退出应用程序
导入时间#计算运行时间
导入操作系统
def使用(程序名称):
打印(“用法:{0}”。格式(程序名))
系统出口(1)
def破解程序(zip文件路径、密码):
打印('[*]正在启动新的破解程序(pid={0},password=“{1}”)。格式(os.getpid(),password))
尝试:
时间。睡眠(1)#XXX:模拟需要一点时间的任务
zipfile.zipfile(zip文件路径)作为zFile:
zFile.extractall(pwd=bytes(密码“utf-8”))
返回密码
除:
一无所获
def main():
如果len(sys.argv)<3:
用法(sys.argv[0])
打印('[*]启动main(pid={0})'.format(os.getpid())
zip\u file\u path=sys.argv[1]
密码\文件\路径=sys.argv[2]
startime=time.time()
实际密码=无
使用mp.Pool()作为池:
def设置_实际_密码(密码):
非本地实际密码
如果输入密码:
打印(“[*]找到密码;正在停止将来的任务”)
pool.terminate()
实际密码=密码
打开(密码\u文件\u路径'r',errors='ignore')作为密码\u文件:
对于密码_文件中的pswd:
pswd=pswd.strip('\n')
apply\u async(cracker,(zip\u file\u path,pswd,),callback=set\u实际\u密码)
pool.close()
pool.join()
如果实际密码为:
打印(“[*]破解密码:“{0}”。格式(实际密码))
其他:
打印(“[*]无法破解密码”)
runtime=round(time.time()-startime,5)
打印(“[*]运行时:”,运行时,“秒”)
系统出口(0)
如果名称=“\uuuuu main\uuuuuuuu”:
main()

以下是来自和的建议的实施:

#/usr/bin/env蟒蛇3
“”“暴力压缩密码。
用法
#!/usr/bin/env python3

import multiprocessing as mp
import zipfile # Handeling the zipfile
import sys # Command line arguments, and quiting application
import time # To calculate runtime
import os

def usage(program_name):
    print("Usage: {0} <path to zipfile> <dictionary>".format(program_name))
    sys.exit(1)

def cracker(zip_file_path, password):
    print('[*] Starting new cracker (pid={0}, password="{1}")'.format(os.getpid(), password))

    try:
        time.sleep(1) # XXX: to simulate the task taking a bit of time
        with zipfile.ZipFile(zip_file_path) as zFile:
            zFile.extractall(pwd=bytes(password, 'utf-8'))
        return password
    except:
        return None

def main():
    if len(sys.argv) < 3:
        usage(sys.argv[0])

    print('[*] Starting main (pid={0})'.format(os.getpid()))

    zip_file_path = sys.argv[1]
    password_file_path = sys.argv[2]
    startime = time.time()
    actual_password = None

    with mp.Pool() as pool:
        def set_actual_password(password):
            nonlocal actual_password
            if password:
                print('[*] Found password; stopping future tasks')
                pool.terminate()
                actual_password = password

        with open(password_file_path, 'r', errors='ignore') as password_file:
            for pswd in password_file:
                pswd = pswd.strip('\n')
                pool.apply_async(cracker, (zip_file_path, pswd,), callback=set_actual_password)

        pool.close()
        pool.join()

    if actual_password:
        print('[*] Cracked password: "{0}"'.format(actual_password))
    else:
        print('[*] Unable to crack password')
    runtime =  round(time.time() - startime, 5)
    print("[*] Runtime:", runtime, 'seconds')
    sys.exit(0)

if __name__ == "__main__":
    main()
#!/usr/bin/env python3
"""Brute force zip password.

Usage: brute-force-zip-password <zip archive> <passwords>
"""
import sys
from multiprocessing import Pool
from time import monotonic as timer
from zipfile import ZipFile

def init(archive): # run at the start of a worker process
    global zfile
    zfile = ZipFile(open(archive, 'rb')) # open file in each process once

def check(password):
    assert password
    try:
        with zfile.open(zfile.infolist()[0], pwd=password):
            return password # assume success
    except Exception as e:
        if e.args[0] != 'Bad password for file':
            # assume all other errors happen after the password was accepted
            raise RuntimeError(password) from e

def main():
    if len(sys.argv) != 3:
        sys.exit(__doc__) # print usage

    start = timer()
    # decode passwords using the preferred locale encoding
    with open(sys.argv[2], errors='ignore') as file, \
         Pool(initializer=init, initargs=[sys.argv[1]]) as pool: # use all CPUs
        # check passwords encoded using utf-8
        passwords = (line.rstrip('\n').encode('utf-8') for line in file)
        passwords = filter(None, passwords) # filter empty passwords
        for password in pool.imap_unordered(check, passwords, chunksize=100):
            if password is not None:  # found
                print("Password: '{}'".format(password.decode('utf-8')))
                break
        else:
            sys.exit('Unable to find password')
    print('Runtime: %.5f seconds' % (timer() - start,))

if __name__=="__main__":
    main()