【问题标题】:Increasing throughput in a python script在 python 脚本中增加吞吐量
【发布时间】:2010-06-22 00:33:42
【问题描述】:

我正在通过 dig 处理来自 DNSBL 的数千个域名列表,创建一个包含 URL 和 IP 的 CSV。这是一个非常耗时的过程,可能需要几个小时。我的服务器的 DNSBL 每十五分钟更新一次。有没有办法提高 Python 脚本的吞吐量以跟上服务器的更新?

编辑:按要求编写脚本。

import re
import subprocess as sp

text = open("domainslist", 'r')
text = text.read()
text = re.split("\n+", text)

file = open('final.csv', 'w')

for element in text:
        try:
            ip = sp.Popen(["dig", "+short", url], stdout = sp.PIPE)
            ip = re.split("\n+", ip.stdout.read())
            file.write(url + "," + ip[0] + "\n")
        except:
            pass

【问题讨论】:

  • 显示脚本 - 或脚本的伪代码。这样我们就可以提出改进建议。 15 分钟内上千的列表应该很容易在 python 的限制范围内。
  • +1,请告诉我们你有什么。顺便说一句,如果我理解正确,很可能是名称解析,而不是脚本本身,这需要很长时间。如果是这种情况,您可能想尝试线程解决方案。
  • 不管实际解决方案如何,几点建议:避免为不同的事物重用相同的变量(text = open...; text = text.read());使用“text.splitlines()”代替正则表达式;避免使用“file”作为变量名,因为它是 Python 2.x 中的关键字(尽管在 Python 3 中不是);并记住关闭你的文件句柄(即使 Python 会为你做这件事,在这种情况下)。

标签: python unix python-multithreading


【解决方案1】:

嗯,可能是名称解析花了您这么长时间。如果算上这些(即,如果 dig 以某种方式很快返回),Python 应该能够轻松处理数千个条目。

也就是说,您应该尝试线程化方法。这将(理论上)同时解析多个地址,而不是顺序解析。您也可以继续使用 dig ,并且为此修改下面的示例代码应该是微不足道的,但是,为了让事情变得有趣(并且希望更 Pythonic),让我们使用现有模块:dnspython

所以,安装它:

sudo pip install -f http://www.dnspython.org/kits/1.8.0/ dnspython

然后尝试以下操作:

import threading
from dns import resolver

class Resolver(threading.Thread):
    def __init__(self, address, result_dict):
        threading.Thread.__init__(self)
        self.address = address
        self.result_dict = result_dict

    def run(self):
        try:
            result = resolver.query(self.address)[0].to_text()
            self.result_dict[self.address] = result
        except resolver.NXDOMAIN:
            pass


def main():
    infile = open("domainlist", "r")
    intext = infile.readlines()
    threads = []
    results = {}
    for address in [address.strip() for address in intext if address.strip()]:
        resolver_thread = Resolver(address, results)
        threads.append(resolver_thread)
        resolver_thread.start()

    for thread in threads:
        thread.join()

    outfile = open('final.csv', 'w')
    outfile.write("\n".join("%s,%s" % (address, ip) for address, ip in results.iteritems()))
    outfile.close()

if __name__ == '__main__':
    main()

如果这证明同时启动太多线程,您可以尝试分批执行,或使用队列(参见http://www.ibm.com/developerworks/aix/library/au-threadingpython/ 示例)

【讨论】:

  • 效果很好,但我不断收到这些错误:文件“/home/okim/dnspython/dns/resolver.py”,第 541 行,_compute_timeout raise Timeout Timeout 有什么想法吗?
  • 显然您的名称服务器无法在默认超时内解析某些名称(可能权威名称服务器没有响应)。如果您想跳过这些,只需将“except resolver.NXDOMAIN:”行更改为“except (resolver.NXDOMAIN, resolver.Timeout):”。如果您想以不同的方式处理这些异常,只需在 NXDOMAIN 之后添加一个新的 except 子句。顺便说一句,NXDOMAIN 会捕获不存在的域。
  • 顺便说一句,如果你发现问题出在你的域名服务器上,你可以用“resolver.default_resolver.nameservers.insert(0, '8.8.8.8')”名义上指定一个。但我只是为了完整起见,更有可能的是,在数千个域名中,其中一些根本没有响应(特别是因为你提到它们来自黑名单)。
  • 是的,我的域名服务器有问题。更改“除外”虽然有效。感谢您的帮助!
【解决方案2】:

这里的大部分时间都花在了对dig 的外部调用上,所以为了提高速度,你需要多线程。这将允许您同时对dig 进行多次调用。例如:Python Subprocess.Popen from a thread。或者,您可以使用 Twisted (http://twistedmatrix.com/trac/)。

编辑:你是对的,其中大部分是不必要的。

【讨论】:

  • +1 表示需要线程调用来挖掘。你应该把这个放在你的答案中。
【解决方案3】:

我会考虑使用纯 Python 库来执行 DNS 查询,而不是委托给 dig,因为调用另一个进程可能会比较耗时。 (当然,在 Internet 上查找任何内容也相对耗时,因此 gilesc 所说的多线程仍然适用)Google 搜索 python dns 将为您提供一些入门选择。

【讨论】:

  • 与执行 DNS 查询所需的时间相比,启动新进程的开销可以忽略不计
  • 是的,但是gilesc的回答已经涵盖了网络延迟。
【解决方案4】:

为了跟上服务器更新的步伐,执行时间必须少于 15 分钟。您的脚本需要 15 分钟才能运行吗?如果不需要 15 分钟,你就完成了!

我会研究缓存和之前运行的差异以提高性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-14
    • 2020-10-13
    • 2014-09-20
    • 1970-01-01
    相关资源
    最近更新 更多