Estoy abriendo un archivo que tiene 100,000 URL. Necesito enviar una solicitud HTTP a cada URL e imprimir el código de estado. Estoy usando Python 2.6, y hasta ahora examiné las muchas formas confusas en que Python implementa subprocesamiento / concurrencia. Incluso he mirado la biblioteca de concurrencia de Python , pero no puedo entender cómo escribir este programa correctamente. ¿Alguien ha encontrado un problema similar? Supongo que generalmente necesito saber cómo realizar miles de tareas en Python lo más rápido posible, supongo que eso significa 'concurrentemente'.
python
http
concurrency
IgorGanapolsky
fuente
fuente
requests.get
yrequests.head
(es decir, una solicitud de página frente a una solicitud de encabezado) devolver diferentes códigos de estado, por lo que este no es el mejor consejoRespuestas:
Solución retorcida:
Esta es ligeramente más rápida que la solución retorcida y usa menos CPU.
fuente
concurrent*2
?conn.close()
. Abrir demasiadas conexiones http puede detener su script en algún momento y consume memoria.Queue
módulo ha sido renombradoqueue
en Python 3. Este es el código Python 2.Una solución que utiliza la biblioteca de red asincrónica de tornado
fuente
Las cosas han cambiado bastante desde 2010 cuando esto se publicó y no he probado todas las otras respuestas, pero he intentado algunas, y descubrí que esto funciona mejor para mí usando python3.6.
Pude obtener alrededor de ~ 150 dominios únicos por segundo que se ejecutan en AWS.
fuente
time1 = time.time()
en la parte superior del ciclo for ytime2 = time.time()
justo después del ciclo for.Los hilos no son absolutamente la respuesta aquí. Proporcionarán cuellos de botella en el proceso y en el núcleo, así como límites de rendimiento que no son aceptables si el objetivo general es "la forma más rápida".
Un poco de
twisted
y suHTTP
cliente asincrónico le daría resultados mucho mejores.fuente
Sé que esta es una vieja pregunta, pero en Python 3.7 puedes hacer esto usando
asyncio
yaiohttp
.Puede leer más al respecto y ver un ejemplo aquí .
fuente
urls= [fetch(construct_fetch_url(u),idx) for idx, u in enumerate(some_URI_list)]
results = await asyncio.gather(*urls)
Usa grequests , es una combinación de solicitudes + módulo Gevent.
GRequests le permite usar Solicitudes con Gevent para hacer Solicitudes HTTP asincrónicas fácilmente.
El uso es simple:
Cree un conjunto de solicitudes no enviadas:
Envíelos todos al mismo tiempo:
fuente
Un buen enfoque para resolver este problema es primero escribir el código requerido para obtener un resultado, luego incorporar código de subprocesos para paralelizar la aplicación.
En un mundo perfecto, esto simplemente significaría iniciar simultáneamente 100,000 hilos que generan sus resultados en un diccionario o lista para su posterior procesamiento, pero en la práctica está limitado en la cantidad de solicitudes HTTP paralelas que puede emitir de esta manera. Localmente, tiene límites en la cantidad de sockets que puede abrir simultáneamente, cuántos hilos de ejecución le permitirá su intérprete de Python. De forma remota, puede estar limitado en el número de conexiones simultáneas si todas las solicitudes son contra un servidor o varios. Estas limitaciones probablemente requerirán que escriba el script de tal manera que solo sondee una pequeña fracción de las URL en cualquier momento (100, como se menciona en otro póster, es probablemente un tamaño de grupo de subprocesos decente, aunque puede encontrar que puede implementar con éxito muchos más).
Puede seguir este patrón de diseño para resolver el problema anterior:
list
odict
en CPython, puede agregar o insertar de forma segura elementos únicos de sus hilos sin bloqueos , pero si escribe en un archivo o requiere una interacción de datos entre hilos más compleja , debe usar un bloqueo de exclusión mutua para proteger este estado de la corrupción .Te sugiero que uses el enhebrado módulo de . Puede usarlo para iniciar y rastrear hilos en ejecución. El soporte de subprocesos de Python es escaso, pero la descripción de su problema sugiere que es completamente suficiente para sus necesidades.
Por último, si desea ver una aplicación directa bonita de una aplicación de red en paralelo escrito en Python, echa un vistazo a ssh.py . Es una pequeña biblioteca que utiliza subprocesos de Python para paralelizar muchas conexiones SSH. El diseño está lo suficientemente cerca de sus requisitos como para que sea un buen recurso.
fuente
Si está buscando obtener el mejor rendimiento posible, es posible que desee considerar el uso de E / S asincrónicas en lugar de subprocesos. La sobrecarga asociada con miles de subprocesos del sistema operativo no es trivial y el cambio de contexto dentro del intérprete de Python agrega aún más. El enhebrado ciertamente hará el trabajo, pero sospecho que una ruta asincrónica proporcionará un mejor rendimiento general.
Específicamente, sugeriría el cliente web asíncrono en la biblioteca Twisted ( http://www.twistedmatrix.com ). Tiene una curva de aprendizaje ciertamente empinada, pero es bastante fácil de usar una vez que dominas el estilo de programación asincrónica de Twisted.
Un tutorial sobre API de cliente web asincrónico de Twisted está disponible en:
http://twistedmatrix.com/documents/current/web/howto/client.html
fuente
Una solución:
Tiempo de prueba:
Pingtime:
fuente
Usar un grupo de subprocesos es una buena opción, y lo hará bastante fácil. Desafortunadamente, python no tiene una biblioteca estándar que haga que los grupos de subprocesos sean extremadamente fáciles. Pero aquí hay una biblioteca decente que debería comenzar: http://www.chrisarndt.de/projects/threadpool/
Ejemplo de código de su sitio:
Espero que esto ayude.
fuente
q_size
> 0, el tamaño de la cola de solicitudes de trabajo es limitado y el grupo de subprocesos se bloquea cuando la cola está llena e intenta colocar más solicitudes de trabajo (verputRequest
método), a menos que también use untimeout
valor positivo paraputRequest
".Cree un
epoll
objeto,abra muchos sockets TCP del cliente,
ajuste sus búferes de envío para que sean un poco más que el encabezado de la solicitud,
envíe un encabezado de solicitud: debe ser inmediato, simplemente colóquelo en un búfer, registre el zócalo en el
epoll
objeto,hágalo
.poll
alepoll
obedecer,lea primero 3 bytes de cada socket de
.poll
,escríbalos a
sys.stdout
seguido de\n
(no vaciar), cierre el socket del cliente.Limite el número de sockets abiertos simultáneamente: maneje los errores cuando se crean sockets. Cree un nuevo socket solo si otro está cerrado.
Ajusta los límites del sistema operativo.
Intente bifurcarse en unos pocos (no muchos) procesos: esto puede ayudar a usar la CPU un poco más efectivamente.
fuente
Para su caso, el enhebrado probablemente servirá, ya que probablemente pasará la mayor parte del tiempo esperando una respuesta. Hay módulos útiles como Queue en la biblioteca estándar que podrían ayudar.
Hice algo similar con la descarga paralela de archivos antes y fue lo suficientemente bueno para mí, pero no estaba en la escala de la que estás hablando.
Si su tarea estaba más vinculada a la CPU, es posible que desee ver el módulo de multiprocesamiento , que le permitirá utilizar más CPU / núcleos / subprocesos (más procesos que no se bloquearán entre sí ya que el bloqueo es por proceso)
fuente
Considere usar Windmill , aunque Windmill probablemente no pueda hacer tantos hilos.
Puede hacerlo con un script Python enrollado a mano en 5 máquinas, cada una de las cuales se conecta a la salida utilizando los puertos 40000-60000, abriendo 100,000 conexiones de puerto.
Además, podría ayudar hacer una prueba de muestra con una aplicación de control de calidad muy bien roscada como OpenSTA para tener una idea de cuánto puede manejar cada servidor.
Además, intente buscar simplemente usando Perl simple con la clase LWP :: ConnCache. Probablemente obtendrá más rendimiento (más conexiones) de esa manera.
fuente
Este retorcido cliente web asíncrono va bastante rápido.
fuente
Descubrí que usar el
tornado
paquete es la forma más rápida y sencilla de lograr esto:fuente
La forma más fácil sería utilizar la biblioteca de subprocesos incorporada de Python.
No son hilos "reales" / del núcleo.Tienen problemas (como la serialización), pero son lo suficientemente buenos. Desea una cola y un grupo de subprocesos. Una opción está aquí , pero es trivial escribir la suya. No puede hacer paralelo a todas las 100,000 llamadas, pero puede disparar 100 (más o menos) al mismo tiempo.fuente