3

我希望在短时间内进行大量反向 DNS 查找。我目前已经使用 socket.gethostbyaddr 和 concurrent.futures 线程池实现了异步查找,但仍然没有看到所需的性能。例如,脚本在 2500 个 IP 地址上完成大约需要 22 分钟。

我想知道是否有更快的方法来做到这一点,而无需求助于 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)

但它似乎没有效果。

4

3 回答 3

3

我发现我的主要问题是 IP 无法解析,因此套接字不遵守其设置的超时并在 30 秒后失败。请参阅Python 2.6 urllib2 超时问题

adns-python是不行的,因为它缺乏对 IPv6 的支持(没有补丁)。

在四处搜索后,我发现了这个:Reverse DNS Lookups with dnspython并在我的代码中实现了一个类似的版本(他的代码也使用了一个可选的线程池并实现了超时)。

最后,我使用 dnspython 和 concurrent.futures 线程池进行异步反向 DNS 查找(请参阅Python:共享主机中的反向 DNS 查找Dnspython:设置查询超时/生命周期)。超时时间为 1 秒,这将 2500 个 IP 地址的运行时间从大约 22 分钟缩短到大约 16 秒。巨大的差异可能归因于套接字上的全局解释器锁定和 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 ""
于 2014-06-08T00:29:44.793 回答
1

由于Global Interpreter Lock,您应该ProcessPoolExecutor改用。 https://docs.python.org/dev/library/concurrent.futures.html#processpoolexecutor

于 2014-06-07T07:14:24.243 回答
0

请使用异步 DNS,其他一切都会给您带来非常糟糕的性能。

于 2014-06-07T05:20:48.030 回答