线程与解释器关闭
我有一段Python代码:
def __init__(self):
self.ip_list=[]
self.queue=Queue()
for i in range(5):
worker=threading.Thread(target=self.__executeCmd, name="executeCmd("+str(i)+")")
worker.setDaemon(True)
worker.start()
self.queue.put(["wget", "-qO-", "http://ipecho.net/plain"])
self.queue.put(["curl", "http://www.networksecuritytoolkit.org/nst/cgi-bin/ip.cgi"])
self.queue.put(["curl", "v4.ident.me"])
self.queue.put(["curl", "ipv4.icanhazip.com"])
self.queue.put(["curl", "ipv4.ipogre.com"])
def __executeCmd(self):
cmd=self.queue.get()
try:
rc=subprocess.check_output(cmd, stderr=open(os.devnull, 'w')).strip()
except:
self.queue.task_done()
return
if self.is_valid_ip(rc)==True:
self.ip_list.append(rc)
self.queue.task_done()
def waitForIP(self, wait_in_sec):
cnt=wait_in_sec*10
while self.ip_list==[]:
time.sleep(0.1)
cnt-=1
if cnt<=0:
return("")
return(self.ip_list[0])
这段代码是用来从五个网址查询外部IP地址,并获取第一个返回结果的。
但是有时候我会收到这样的信息(我通过电子邮件收到,因为这个任务是通过定时任务(crontab)启动的):
Exception in thread executeCmd(0) (most likely raised during interpreter shutdown):
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
File "/usr/lib/python2.7/threading.py", line 505, in run
File "/home/dede/bin/tunnel_watchdog.py", line 115, in __executeCmd
File "/usr/lib/python2.7/Queue.py", line 65, in task_done
File "/usr/lib/python2.7/threading.py", line 296, in notifyAll
<type 'exceptions.TypeError'>: 'NoneType' object is not callable
我觉得这是因为脚本已经结束了,但还有一个线程在运行,然后才从subprocess.check_output()中返回结果。
有没有办法避免这种情况(不需要等所有五个网址都返回数据)?
1 个回答
1
这个项目比看起来简单多了。这里有一个使用 multiprocessing
模块的实现方法。
这个 imap_unordered
函数可以同时运行多个任务,并且会先返回完成的任务结果。外层的函数会检查这个结果。如果结果没问题,就会打印出来,然后结束任务池,整个程序也就退出了。它不会等其他任务完成。
import multiprocessing, re, subprocess, sys
CMD_LIST = [
["wget", "-qO-", "http://ipecho.net/plain"],
["curl", '-s', "http://www.networksecuritytoolkit.org/nst/cgi-bin/ip.cgi"],
["curl", '-s', "v4.ident.me"],
["curl", '-s', "ipv4.icanhazip.com"],
["curl", '-s', "ipv4.ipogre.com"],
]
ip_pat = re.compile('[0-9.]{7,}')
pool = multiprocessing.Pool(5)
for output in pool.imap_unordered(subprocess.check_output, CMD_LIST):
print 'output:',output
m = ip_pat.search(output)
if m:
print 'GOT IP:', m.group(0)
pool.terminate()
sys.exit(0)
print 'no IP found'