Python: ускорить обратный поиск DNS

Я планирую запустить обратный DNS на 47 миллионов ips. Вот мой код

with open(file,'r') as f:
    with open ('./ip_ptr_new.txt','a') as w:

        for l in f:

            la = l.rstrip('\n')
            ip,countdomain = la.split('|')
            ips.append(ip)

           try:
                ais = socket.gethostbyaddr(ip)
                print ("%s|%s|%s" % (ip,ais[0],countdomain), file = w)    
           except:
                print ("%s|%s|%s" % (ip,"None",countdomain), file = w)

В настоящее время это очень медленно. У кого-нибудь есть предложения по ускорению?


person UserYmY    schedule 09.07.2015    source источник
comment
Запуск нескольких потоков/процессов   -  person matino    schedule 09.07.2015
comment
@matino у моей машины только два процессора. и с модулем многопроцессорности python два не ускорит его так сильно. Можно подробнее?   -  person UserYmY    schedule 09.07.2015
comment
То, что у вас 2 процессора, не означает, что вы можете запускать только 2 процесса одновременно. Попробуйте запустить с большим количеством - маловероятно, что этот код привязан к процессору.   -  person Tom Dalton    schedule 09.07.2015
comment
Ну, вы можете использовать 2 процесса, каждый из которых порождает несколько потоков, каждый поток 1) читает только часть файла 2) эта часть ищет хост   -  person matino    schedule 09.07.2015
comment
@matino Спасибо. Мне было бы очень полезно, если бы вы могли написать ответ отдельно.   -  person UserYmY    schedule 09.07.2015


Ответы (3)


Попробуйте использовать многопроцессорный модуль. Я рассчитал производительность около 8000 ips и получил следующее:

#dns.py
real    0m2.864s
user    0m0.788s
sys     0m1.216s


#slowdns.py
real    0m17.841s
user    0m0.712s
sys     0m0.772s


# dns.py
from multiprocessing import Pool
import socket
def dns_lookup(ip):
    ip, countdomain = ip
    try:
        ais = socket.gethostbyaddr(ip)
        print ("%s|%s|%s" % (ip,ais[0],countdomain))
    except:
        print ("%s|%s|%s" % (ip,"None",countdomain))

if __name__ == '__main__':
    filename = "input.txt"
    ips = []
    with open(filename,'r') as f:
        with open ('./ip_ptr_new.txt','a') as w:
            for l in f:
                la = l.rstrip('\n')
                ip,countdomain = la.split('|')
                ips.append((ip, countdomain))
    p = Pool(5)
    p.map(dns_lookup, ips)





#slowdns.py
import socket
from multiprocessing import Pool

filename = "input.txt"
if __name__ == '__main__':
    ips = []
    with open(filename,'r') as f:
        with open ('./ip_ptr_new.txt','a') as w:
            for l in f:
               la = l.rstrip('\n')
               ip,countdomain = la.split('|')
               ips.append(ip)
               try:
                    ais = socket.gethostbyaddr(ip)
                    print ("%s|%s|%s" % (ip,ais[0],countdomain), file = w)
               except:
                    print ("%s|%s|%s" % (ip,"None",countdomain), file = w)
person vHalaharvi    schedule 09.07.2015
comment
Спасибо за вашу помощь. Проблема в том, что количество ips очень много и чтобы вывести их в список требуется почти 90% памяти. Есть ли способ прочитать строку за строкой и передать ее многопроцессорному модулю/.? - person UserYmY; 09.07.2015
comment
Извините, я пропустил это требование. В этом случае вы не можете использовать список, вместо этого вам придется использовать очередь. Чтение из больших файлов все равно будет в порядке, поскольку python использует генераторы, а не списки. Пожалуйста, проверьте эту тему. stackoverflow.com/questions/14677287/ - person vHalaharvi; 09.07.2015
comment
хм Спасибо. Но я до сих пор не знаю, как использовать очередь в этом случае. - person UserYmY; 10.07.2015
comment
Хорошо, я посмотрю, смогу ли я сегодня опубликовать редактирование с фактическим кодом. - person vHalaharvi; 10.07.2015

Одним из решений здесь является использование команды оболочки nslookup с параметром timeout. Возможно, команда хоста... Пример не идеальный, но полезный!

def sh_dns(ip,dns):
   a=subprocess.Popen(['timeout','0.2','nslookup','-norec',ip,dns],stdout=subprocess.PIPE)
   sortie=a.stdout.read()
   tab=str(sortie).split('=')
   if(len(tab)>1):
     return tab[len(tab)-1].strip(' \\n\'')
   else:
     return ""
person YB45    schedule 20.12.2017

Недавно нам тоже пришлось столкнуться с этой проблемой. Запуск нескольких процессов не обеспечивал достаточно хорошего решения. Обработка нескольких миллионов IP-адресов с мощной машины AWS может занять несколько дней. Хорошо сработало использование Amazon EMR, на кластер из 10 машин ушло около получаса. Вы не можете слишком сильно масштабироваться с одной машиной (и обычно с одним сетевым интерфейсом), поскольку это задача с интенсивным использованием сети. Использование Map Reduce на нескольких машинах определенно сработало.

person Elhanan Mishraky    schedule 05.05.2019