Después de muchas veces escribimos un reptil, para alcanzar los requisitos encontrarán mucho para mejorar el lugar, que es una velocidad muy punto importante es el rastreo. En este artículo se explica cómo utilizar el código a través de la multi-proceso, multi-hilo, corrutina para mejorar la velocidad de rastreo. Nota: No hacemos una idea de la teoría y principio, todo en su código.
En segundo lugar, sincrónica
En primer lugar, escribir reptiles simplificados, cada segmento funcional, la programación funcional conducta consciente. El código siguiente es un acceso a objetos 300 página Baidu y devolver un código de estado, en el que parse_1
la función se puede establecer el número de ciclos, cada ciclo del número actual ciclo (a partir de 0) y la URL entrante parse_2
función.
las solicitudes de importación parse_1 def (): url = 'https://www.baidu.com' para i en el rango de (300): parse_2 (url) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
El rendimiento se consume principalmente en la solicitud IO, cuando la URL de solicitud utilizando el modo de un único subproceso conducirá inevitablemente a la espera
El código de ejemplo es una lógica típica de serie, parse_1
el número de ciclos hasta la transferencia y la url parse_2
, parse_2
solicitud y devuelve el código de estado parse_1
continuará iterando paso se repitió una vez que antes
En tercer lugar, multi-hilo
Debido a que sólo hay tiempo CPU un hilo en cada escala en la ejecución del programa, de modo multi-roscado proceso en realidad aumenta el uso resulta en una mejor utilización de la CPU
biblioteca multi-hilo que hay muchos, aquí concurrent.futures
es ThreadPoolExecutor
demostrar. Introducción ThreadPoolExecutor
biblioteca porque es más concisa que cualquier otro código de la biblioteca
Por conveniencia de ilustración, el siguiente código si se partes recién añadido, la primera línea de código plus> Símbolo facilitar la observación de la ilustración, la necesidad de la operación real que ser eliminado
las solicitudes de importación > Desde concurrent.futures ThreadPoolExecutor importación parse_1 def (): url = 'https://www.baidu.com' # Crear grupo de subprocesos > Piscina = ThreadPoolExecutor (6) para i en el rango de (300): > Pool.submit (parse_2, url) > Pool.shutdown (espera = True) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
Se sincroniza con relativamente asíncrona . Asíncrono es independiente el uno del otro, continuar haciendo sus propias cosas a la espera de un evento, no es necesario esperar a que este evento después de la finalización de la obra. hilo asíncrono es lograr una forma, que es el procesamiento asincrónico medios multi-threading asíncronos que no saben los resultados, a veces es necesario conocer los resultados, se puede utilizar una devolución de llamada
las solicitudes de importación de concurrent.futures ThreadPoolExecutor importación # Añadir una función de devolución de llamada > Def callback (futuro): > Impresión (future.result ()) parse_1 def (): url = 'https://www.baidu.com' piscina = ThreadPoolExecutor (6) para i en el rango de (300): > Resultados = pool.submit (parse_2, url) # pasos clave de devolución de llamada > Results.add_done_callback (devolución de llamada) pool.shutdown (espera = True) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
P ython un multi-hilo innumerables personas han criticado GIL (Intérprete bloqueo global) , pero pertenecen a la tarea IO-intensivos multi-roscado sigue siendo muy adecuado para el rastreo de las páginas de esta mayoría.
En cuarto lugar, multi-proceso
Multi-proceso implementado en dos formas: ProcessPoolExecutor
y multiprocessing
1. ProcessPoolExecutor
Y multi-hilo ThreadPoolExecutor
similares
las solicitudes de importación > Concurrent.futures de importación ProcessPoolExecutor parse_1 def (): url = 'https://www.baidu.com' # Crear grupo de subprocesos > Piscina = ProcessPoolExecutor (6) para i en el rango de (300): > Pool.submit (parse_2, url) > Pool.shutdown (espera = True) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
Buscar cambios en el nombre de dos clases, el código es muy simple, la empatía también se puede añadir una devolución de llamada función
las solicitudes de importación de concurrent.futures ProcessPoolExecutor importación > Def callback (futuro): > Impresión (future.result ()) parse_1 def (): url = 'https://www.baidu.com' piscina = ProcessPoolExecutor (6) para i en el rango de (300): > Resultados = pool.submit (parse_2, url) > Results.add_done_callback (devolución de llamada) pool.shutdown (espera = True) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
2. multiprocesamiento
mirada directa en el código, todo en los comentarios.
las solicitudes de importación > Multiprocesamiento de importación piscina parse_1 def (): url = 'https://www.baidu.com' # Piscina construida > = piscina piscina (procesos = 5) # Almacenar resultados > Res_lst = [] para i en el rango de (300): # Formar parte del grupo de tareas > Res = pool.apply_async (func = parse_2, args = (url,)) # Consecuencia Adquisición completó (necesidad de quitar) > res_lst.append (res) # Almacenar el resultado final (también se pueden almacenar directamente o imprimir) > Good_res_lst = [] > Para la resolución de res_lst: # Obtener resultados después de usar el proceso de adquisición > Good_res = res.get () # Resultado de discriminación es bueno o malo > Si good_res: > good_res_lst.append (good_res) # Apague y esperar a la finalización > Pool.close () > Pool.join () def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
Se puede ver multiprocessing
la base de código un poco tedioso, pero apoyar una mayor expansión. Multi-proceso y multi-threading puede realmente alcanzar el objetivo de acelerar, pero si están bloqueando hilo o periferia del proceso será una pérdida, por lo que hay una mejor manera ......
En quinto lugar, no bloqueo asíncrono
Corrutina + devolución de llamada con la dinámica de no bloqueo colaboración asíncrona podemos lograr el propósito, la naturaleza tomó sólo un hilo, por lo que en gran medida el uso de los recursos
Classic es el uso de asíncrono no bloqueante asyncio
biblioteca + yield
, con el fin de facilitar el uso de la aparición gradual de la capa superior del paquete aiohttp
, a fin de comprender mejor la asíncrono no bloqueante mejor comprensión de asyncio
la biblioteca. Y gevent
es muy fácil de implementar biblioteca corrutina
las solicitudes de importación > Mono de importación GEvent # Mono alma parche se ejecuta en colaboración > Monkey.patch_all () > Importar peddled parse_1 def (): url = 'https://www.baidu.com' # Crear una lista de tareas > Tasks_list = [] para i en el rango de (300): > Task = gevent.spawn (parse_2, url) > Tasks_list.append (tarea) > Gevent.joinall (tasks_list) def parse_2 (URL): respuesta = requests.get (url) impresión (response.status_code) Si __name__ == '__main__': parse_1 ()
GEvent puede considerablemente la velocidad, también introduce un nuevo problema: si no queremos demasiado rápido como para causar demasiada carga en el servidor de cómo hacerlo? Si se trata de un multi-proceso de construcción multi-roscado de la piscina, se puede controlar el número de la piscina. Si desea controlar la velocidad con la GEvent también tiene un buen enfoque: cola de construcción. GEvent también proporcionó clase Quene , cambie el código siguiente más grande
las solicitudes de importación mono de importación GEvent monkey.patch_all () importación peddled > Importación de cola gevent.queue parse_1 def (): url = 'https://www.baidu.com' = Tasks_list [] # Cola de instanciación > Quene = Queue () para i en el rango de (300): Todas las colas presionados url # > Quene.put_nowait (url) cola de dos # > Para _ en el rango de (2): > Task = gevent.spawn (parse_2) > Tasks_list.append (tarea) gevent.joinall (tasks_list) # No necesitamos pasar parámetros, estamos en la cola > Def parse_2 (): # Ciclo si la cola está vacía > Mientras no quene.empty (): # Pop cola > Url = quene.get_nowait () respuesta = requests.get (url) Análisis de estado de la cola # > Impresión (quene.qsize (), response.status_code) Si __name__ == '__main__': parse_1 ()
conclusión
Estos son varios método de aceleración comúnmente usado. Si está interesado puede utilizar módulo de prueba de código de tiempo determina el tiempo de ejecución. Acelerar el reptil es una habilidad importante, pero la velocidad se controla adecuadamente los trabajadores de reptiles buenos hábitos, no se dé demasiada presión en el servidor, bye ~