Aumentar el rendimiento en un script en Python
-
28-09-2019 - |
Pregunta
Estoy procesar una lista de miles de nombres de dominio de una DNSBL través de excavación, la creación de un archivo CSV de direcciones URL y direcciones IP. Este es un proceso que consume mucho tiempo que puede durar varias horas. DNSBL de mi servidor actualiza cada quince minutos. ¿Hay alguna manera de aumentar el rendimiento en mi script de Python para mantener el ritmo de actualizaciones del servidor?
Editar . El guión, conforme a lo solicitado
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
Solución
Bueno, es probable que la resolución de nombres que usted está tomando tanto tiempo. Si se cuenta a eso (es decir, si de alguna manera dig vuelto muy rápidamente), Python debe ser capaz de hacer frente a miles de entradas fácilmente.
Dicho esto, usted debe tratar de un enfoque roscado. Eso sería (teóricamente) resolver varias direcciones al mismo tiempo, en lugar de secuencialmente. Se podía así continúa utilizando excavación para eso, y debe ser trivial para modificar mi código de ejemplo a continuación para eso, pero, para hacer cosas interesantes (y es de esperar más Pythonic), vamos a utilizar un módulo existente para ello: dnspython
Así, instalarlo con:
sudo pip install -f http://www.dnspython.org/kits/1.8.0/ dnspython
Y luego probar algo parecido a lo siguiente:
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()
Si eso prueba para comenzar a demasiados hilos al mismo tiempo, usted podría intentar hacerlo en lotes, o el uso de una cola (ver http://www.ibm.com/developerworks/aix/library/au-threadingpython/ para un ejemplo)
Otros consejos
La gran mayoría de las veces aquí se gasta en las llamadas externas a dig
, por lo que para mejorar la velocidad, usted tendrá que multihilo. Esto le permitirá ejecutar varias llamadas a dig
al mismo tiempo. Véase, por ejemplo: Python subprocess.Popen de un hilo. O bien, puede utilizar trenzado ( http://twistedmatrix.com/trac/ ).
EDIT:. Tiene razón, gran parte de eso era innecesario
Me volvería a considerar el uso de una biblioteca pura en Python para hacer las consultas DNS, en lugar de delegar en dig
, debido a la invocación de otro proceso puede ser relativamente mucho tiempo. (Por supuesto, mirando cualquier cosa en Internet también es relativamente mucho tiempo, así que lo que gilesc dicho sobre multithreading todavía se aplica) Una búsqueda en Google para pitón DNS le dará algunas opciones para empezar a utilizar.
Con el fin de seguir el ritmo de las actualizaciones de servidor, hay que tener menos de 15 minutos en ejecutarse. ¿Su escritura de tomar 15 minutos para correr? Si no toma 15 minutos, ya está!
Yo investigaría almacenamiento en caché y las diferenciaciones de las ejecuciones anteriores con el fin de aumentar el rendimiento.