Увеличение пропускной способности в скрипте Python - PullRequest
2 голосов
/ 22 июня 2010

Я обрабатываю список тысяч доменных имен из DNSBL через dig, создавая CSV из URL и IP-адресов. Это очень трудоемкий процесс, который может занять несколько часов. 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

Ответы [ 4 ]

2 голосов
/ 22 июня 2010

Ну, это, вероятно, разрешение имени, которое займет у вас так много времени.Если вы посчитаете это (т. Е. Если копание каким-то образом вернулось очень быстро), Python сможет легко обрабатывать тысячи записей.

Тем не менее, вы должны попробовать многопоточный подход.Это (теоретически) разрешит несколько адресов одновременно, а не последовательно.С тем же успехом вы могли бы продолжать использовать dig для этого, и было бы тривиально изменить мой пример кода ниже для этого, но, чтобы сделать вещи интересными (и, надеюсь, более питоническими), давайте использовать для этого существующий модуль: 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/ для примера)

2 голосов
/ 22 июня 2010

Подавляющее большинство времени здесь тратится на внешние вызовы на dig, поэтому для повышения этой скорости вам потребуется многопоточность. Это позволит вам выполнить несколько звонков на dig одновременно. См. Например: Подпроцесс Python. Открыть из потока . Или вы можете использовать Twisted (http://twistedmatrix.com/trac/).

РЕДАКТИРОВАТЬ: Вы правы, большая часть этого была ненужной.

0 голосов
/ 22 июня 2010

Чтобы идти в ногу с обновлениями сервера, требуется менее 15 минут для выполнения.Ваш сценарий занимает 15 минут?Если это не займет 15 минут, все готово!

Я бы исследовал кеширование и различия из предыдущих прогонов, чтобы повысить производительность.

0 голосов
/ 22 июня 2010

Я бы подумал об использовании чистой библиотеки Python для выполнения DNS-запросов, а не о делегировании на dig, потому что вызов другого процесса может быть относительно длительным.(Конечно, поиск чего-либо в Интернете также относительно трудоемкий, поэтому то, что сказал Гилеск о многопоточности, все еще применимо) Поиск в Google по запросу python dns даст вам несколько вариантов, с которых можно начать.

...