Python如何中断多个线程
我在读一本书《Violent Python》,里面有个例子是教我怎么用字典来破解zip文件的密码。我有两个问题。首先,书里说要用多线程来提高性能,但我测试了一下(我知道用time.time()来计时不是最好的方法),结果发现不使用多线程的情况下快了大约十二秒。这是因为启动线程需要时间吗?第二,如果我不使用线程的话,一旦找到正确的密码,我可以通过打印结果并输入exit(0)来立刻结束程序。有没有办法在使用线程的情况下也能做到这一点,也就是说一旦找到结果就能同时结束所有其他线程呢?
import zipfile
from threading import Thread
import time
def extractFile(z, password, starttime):
try:
z.extractall(pwd=password)
except:
pass
else:
z.close()
print('PWD IS ' + password)
print(str(time.time()-starttime))
def main():
start = time.time()
z = zipfile.ZipFile('test.zip')
pwdfile = open('words.txt')
pwds = pwdfile.read()
pwdfile.close()
for pwd in pwds.splitlines():
t = Thread(target=extractFile, args=(z, pwd, start))
t.start()
#extractFile(z, pwd, start)
print(str(time.time()-start))
if __name__ == '__main__':
main()
2 个回答
1
这段代码运行得很慢,因为Python有一个叫做全局解释器锁的东西,这意味着在任何时候只能有一个线程在执行。这就导致了在Python中,多线程的代码比单线程的代码运行得更慢。如果你想要创建一个真正的多线程应用程序,就需要使用多进程模块。
如果你想要跳出线程并获取返回值,可以使用os._exit(1)
。首先,在文件的顶部导入os模块:
import os
然后,把你的extractFile
函数改成使用os._exit(1)
:
def extractFile(z, password, starttime):
try:
z.extractall(pwd=password)
except:
pass
else:
z.close()
print('PWD IS ' + password)
print(str(time.time()-starttime))
os._exit(1)
2
在CPython中,有个叫做全局解释器锁("GIL")的东西,它限制了同时只能有一个线程在执行Python的字节码。
所以在这个应用中,使用multiprocessing.Pool
的map
方法可能更好,因为每次尝试都是独立的,不会互相影响;
import multiprocessing
import zipfile
def tryfile(password):
rv = passwd
with zipfile.ZipFile('test.zip') as z:
try:
z.extractall(pwd=password)
except:
rv = None
return rv
with open('words.txt') as pwdfile:
data = pwdfile.read()
pwds = data.split()
p = multiprocessing.Pool()
results = p.map(tryfile, pwds)
results = [r for r in results if r is not None]
这段代码默认会启动和你电脑核心数一样多的进程。它会在这些进程中不断用不同的密码来运行tryfile()
,直到密码列表pwds
用完为止,然后收集结果并返回。最后的列表推导是为了去掉那些结果为None
的项。
需要注意的是,这段代码可以改进一下,让它在找到密码后就停止map
。那样的话,你可能需要用到map_async
和一个共享变量。此外,最好只加载一次压缩文件,然后在多个进程中共享。