我希望在很短的时间内进行大量的反向DNS查找。我目前使用socket.gethostbyaddr和concurrent.futures线程池实现了异步查找,但仍然没有看到所需的性能。例如,脚本大约需要22分钟才能完成2500个IP地址。
我想知道是否有更快的方法可以做到这一点而不诉诸adns-python之类的东西。我发现这个http://blog.schmichael.com/2007/09/18/a-lesson-on-python-dns-and-threads/提供了一些额外的背景。
代码段:
ips = [...]
with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
list(pool.map(get_hostname_from_ip, ips))
def get_hostname_from_ip(ip):
try:
return socket.gethostbyaddr(ip)[0]
except:
return ""
我认为问题的一部分是许多IP地址没有解决和超时。我试过了:
socket.setdefaulttimeout(2.0)
但它似乎没有效果。
答案 0 :(得分:3)
我发现我的主要问题是IP无法解决,因此套接字不遵守设置超时并在30秒后失败。请参阅Python 2.6 urlib2 timeout issue。
由于缺乏对IPv6的支持(没有补丁),adns-python 是不合适的。
搜索后我发现:Reverse DNS Lookups with dnspython并在我的代码中实现了类似的版本(他的代码也使用了一个可选的线程池并实现了超时)。
最后,我使用dnspython和concurrent.futures线程池进行异步反向DNS查找(请参阅Python: Reverse DNS Lookup in a shared hosting和Dnspython: Setting query timeout/lifetime)。超时为1秒时,2500个IP地址的运行时间从大约22分钟减少到大约16秒。差异很大可能归因于套接字上的Global Interpreter Lock和30秒超时。
代码段:
import concurrent.futures
from dns import resolver, reversename
dns_resolver = resolver.Resolver()
dns_resolver.timeout = 1
dns_resolver.lifetime = 1
ips = [...]
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
results = list(pool.map(get_hostname_from_ip, ips))
def get_hostname_from_ip(ip):
try:
reverse_name = reversename.from_address(ip)
return dns_resolver.query(reverse_name, "PTR")[0].to_text()[:-1]
except:
return ""
答案 1 :(得分:1)
由于Global Interpreter Lock,您应该使用ProcessPoolExecutor
。
https://docs.python.org/dev/library/concurrent.futures.html#processpoolexecutor
答案 2 :(得分:0)
请使用asynchronous DNS,其他一切都会给你带来很差的表现。