Presentación del caso del reptil Python: Python multi-threaded, multi-proceso, corrutina

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. 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 ~

Publicados 151 artículos originales · ganado elogios 4 · Vistas a 10000 +

Supongo que te gusta

Origin blog.csdn.net/weixin_46089319/article/details/105365180
Recomendado
Clasificación