python3 que, el nuevo módulo multiproceso y multiproceso Afortunadamente - Coroutine corrutina

cartilla

Las versiones más recientes de todos los sistemas python3 se actualizan a python3.7, y luego actualizar el código, encontrar el cambio de versión sigue siendo muy grande, más o hasta que esté hecho el uso de ETL o el funcionamiento de algunos API python2.7, no esperaba que el cambio en pitón tan grande que parece que está todavía demasiado anticuado. Así pues, en busca de información y saber casi al aprendizaje en línea oficial, véase un artículo sobre el artículo corrutina muy esclarecedor, que deberían ser más uso de esta función, multi-proceso antes de usar multihilo efecto no es evidente, pero corrutinas debe ser un arma eficaz pitón.

prefacio

Además de multi-proceso y multi-roscado gran sobrecarga creado el exterior hay una difícil de curar el defecto, el problema es la colaboración entre entre los procesos de tratamiento o hilos, ya que depende de multi-proceso y programas multi-roscados son por lo general en el caso de un desbloqueo que no es controlable, pero corrutinas puede ser la solución perfecta para los problemas de coordinación, para determinar la programación entre corrutinas por el usuario.

Como sabemos, porque hay Python GIL (Global Interpreter Lock) estas cosas, no hay una verdadera multiproceso, multiprocesamiento y por lo tanto va a utilizar la concurrencia en muchos casos, y las aplicaciones multitarea en Python también prestar atención a las áreas clave de sincronización , menos conveniente, multi-hilo y multi-proceso en lugar de utilizar co-rutinas es una opción buena, porque característica atractiva: la iniciativa de llamada / estado de salida, cambio de contexto evitar la CPU y así sucesivamente ...

corrutina

concepto básico

Corrutinas, también conocidos como Coroutine , la instrucción de sintaxis aguardan por asíncrono /, que es la forma recomendada para escribir aplicaciones asíncronas.

Entenderse literalmente, es decir, la rutina para ejecutar simultáneamente, es la relación de la rosca (rosca) orden más fino de la facilidad de hilo, caracterizado por que permite al usuario salir de la llamada activa y activa, suspende la rutina actual y devuelve el valor o para realizar otras tareas, a continuación, volver al punto de parada original de continuar. Espera, hace esto extraño? Todos sabemos que se llevan a cabo las funciones lineales generales, es imposible decir la mitad de la aplicación de la declaración, espere un minuto y se dirigió al mismo lugar para continuar. Sin embargo, algunos pitón familiarizado (u otros lenguajes dinámicos) de los zapatos para niños todos saben que esto se puede hacer, la respuesta es utilizar la instrucción rendimiento. De hecho, aquí queremos agradecer el trabajo para nosotros hacer un sistema operativo (OS), porque tiene getcontext y swapcontext estas características, a través de llamadas al sistema, se puede guardar el estado y el contexto juntos, para cambiar a otro contexto, estas características para lograr la co-rutina proporciona la base para la subyacente. Las interrupciones de funcionamiento del sistema y mecanismo de trampas para lograr esto era proporcionar una posibilidad, por lo que podría ser similar a la siguiente:

>>> import asyncio

>>> async def main():
...     print('hello')
...     await asyncio.sleep(1)
...     print('world')

>>> asyncio.run(main())
hello
world

generador apreciado (generador)

generadores aprendidas y estudiantes iteradores deben saber que hay pitón palabra clave yield, el rendimiento puede llegar a ser una función de un generador, con una rentabilidad diferente, el estado cedería ahorro de valor de retorno de la función en la función, por lo que el próximo tiempo de atención vamos a seguir para realizar una función del último estado, que comenzó a partir de la próxima rendimiento declaración de hacerlo tiene muchos beneficios, tales como queremos generar una serie de columnas, espacio de almacenamiento, si el número de columnas es demasiado grande, pero sólo tenemos que acceder al frente varios elementos, el rendimiento es muy útil, que implementa el mecanismo de este cómputo mientras circula, el ahorro de espacio de almacenamiento y mejorar la eficiencia operativa.

corrutina correr

  1. asyncio.run() La función se utiliza para ejecutar el punto de entrada de más alto nivel ") principal (" Función

  2. Espera un co-rutina. El segmento de código siguiente imprimirá "Hola" después de esperar durante un segundo y, a continuación, de nuevo a la espera para la impresión de "mundo" después de 2 segundos:

    import asyncio
    import time
    
    async def say_after(delay, what):
        await asyncio.sleep(delay)
        print(what)
    
    async def main():
        print(f"started at {time.strftime('%X')}")
    
        await say_after(1, 'hello')
        await say_after(2, 'world')
    
        print(f"finished at {time.strftime('%X')}")
    
    asyncio.run(main())
    
  3. asyncio.create_task()Función se utiliza para simultáneamente ejecutar como asyncio 任务corrutina pluralidad.

    async def main():
        task1 = asyncio.create_task(
            say_after(1, 'hello'))
    
        task2 = asyncio.create_task(
            say_after(2, 'world'))
    
        print(f"started at {time.strftime('%X')}")
    
        # Wait until both tasks are completed (should take
        # around 2 seconds.)
        await task1
        await task2
    
        print(f"finished at {time.strftime('%X')}")
    

Los objetos pueden esperar

Si un objeto se puede utilizar en la declaración esperan, entonces es puede esperar objetos. Muchos API asyncio están diseñados para aceptar los objetos pueden esperar.

Los objetos pueden esperar tres tipos principales: la co-rutina, tareas, y futuro .

corrutina

Python corrutina perteneciente puede esperar a que el objeto, y por lo tanto puede ser de espera en otra corrutina:

import asyncio

async def nested():
    return 42

async def main():
    # Nothing happens if we just call "nested()".
    # A coroutine object is created but not awaited,
    # so it *won't run at all*.
    nested()

    # Let's do it differently now and await it:
    print(await nested())  # will print "42".

asyncio.run(main())

importante

En este documento, "co-rutinas" utilizan para representar dos conceptos estrechamente relacionados:

  • función Coroutine : como se define en la forma async defde una función;
  • objetos co-rutina : LLAMADA función corrutina objeto devuelto.

asyncio también es compatible con el legado generador basado en la co-rutina.

tarea

Tarea se utiliza para establecer el calendario de los concurrentes corrutina ejecución.

Cuando un corrutina por asyncio.create_task()otras funciones se empaquetan como tarea que automáticamente corrutina listo para funcionar de inmediato en el calendario:

import asyncio

async def nested():
    return 42

async def main():
    # Schedule nested() to run soon concurrently
    # with "main()".
    task = asyncio.create_task(nested())

    # "task" can now be used to cancel "nested()", or
    # can simply be awaited to wait until it is complete:
    await task

asyncio.run(main())

objeto futuro

FutureEs un especial de bajo nivel puede esperar objeto que representa una operación asíncrona de que el resultado final .

Cuando un objeto futuro es de esperar , que los medios corrutina quedará pendiente hasta que el objeto se haya completado Future operativo en otro lugar.

En asyncio requerida para permitir el uso de devolución de llamada basado Future código objeto a través de async / esperan.

En circunstancias normales, no hay necesidad de crear un código objeto Futuro en el nivel de aplicación.

Futuro objetos a veces expuesto al usuario por la biblioteca y algunos API asyncio, que puede ser utilizado como objetos de espera:

async def main():
    await function_that_returns_a_future_object()

    # this is also valid:
    await asyncio.gather(
        function_that_returns_a_future_object(),
        some_python_coroutine()
    )

Un buen ejemplo de los retornos de función de bajo nivel el objeto es loop.run_in_executor().

Al mismo tiempo la ejecución de tareas

awaitable asyncio.gather (* AWS , bucle = ninguno , return_exceptions = FALSE )

Concurrente operación AWS secuencia puede esperar para el objeto .

Si AWS de un objeto pueden esperar corrutina, se añade automáticamente como una planificación de la tarea.

Si todos los objetos wait completado con éxito, el resultado será una lista de todos los valores de retorno de la polimerización de. Orden del valor del resultado AWS mismo objeto puede estar esperando la orden.

Si return_exceptions es False(por defecto), causada por la primera excepción se propaga inmediatamente a la espera de gather()la tarea. AWS secuencia de otros objetos puede esperar no se cancelará y continuará funcionando.

Si return_exceptions es True, el resultado será anormal y exitoso como el procesamiento y la agregación a la lista de resultados.

Si gather() cancela , todos los presentados (que no hayan finalizado) puede esperar a que el objeto se cancelará .

Si AWS cualquier secuencia o un objeto de tarea futura es cancelado , que se activarán según CancelledErrorel mismo proceso - en cuyo caso la gather()llamada no se cancelará. Esto es para evitar Tarea / Future ha presentado una cancelación causa otras tareas / Future también ha sido cancelada.

import asyncio

async def factorial(name, number):
    f = 1
    for i in range(2, number + 1):
        print(f"Task {name}: Compute factorial({i})...")
        await asyncio.sleep(1)
        f *= i
    print(f"Task {name}: factorial({number}) = {f}")

async def main():
    # Schedule three calls *concurrently*:
    await asyncio.gather(
        factorial("A", 2),
        factorial("B", 3),
        factorial("C", 4),
    )

asyncio.run(main())

# Expected output:
#
#     Task A: Compute factorial(2)...
#     Task B: Compute factorial(2)...
#     Task C: Compute factorial(2)...
#     Task A: factorial(2) = 2
#     Task B: Compute factorial(3)...
#     Task C: Compute factorial(3)...
#     Task B: factorial(3) = 6
#     Task C: Compute factorial(4)...
#     Task C: factorial(4) = 24

Ejemplos de reptiles

Use los reptiles que se arrastran Top250 berros

from lxml import etree
from time import time
import asyncio
import aiohttp

url = "https://movie.douban.com/top250"
header = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36",
    "content-type": "text/plain;charset=UTF-8",
}


async def fetch_content(url):
    # await asyncio.sleep(1) # 防止请求过快 等待1秒
    async with aiohttp.ClientSession(
        headers=header, connector=aiohttp.TCPConnector(ssl=False)
    ) as session:
        async with session.get(url) as response:
            return await response.text()


async def parse(url):
    page = await fetch_content(url)
    html = etree.HTML(page)

    xpath_movie = '//*[@id="content"]/div/div[1]/ol/li'
    xpath_title = './/span[@class="title"]'
    xpath_pages = '//*[@id="content"]/div/div[1]/div[2]/a'
    xpath_descs = './/span[@class="inq"]'
    xpath_links = './/div[@class="info"]/div[@class="hd"]/a'

    pages = html.xpath(xpath_pages)  # 所有页面的链接都在底部获取
    fetch_list = []
    result = []

    for element_movie in html.xpath(xpath_movie):
        result.append(element_movie)

    for p in pages:
        fetch_list.append(url + p.get("href"))  # 解析翻页按钮对应的链接 组成完整后边页面链接

    tasks = [fetch_content(url) for url in fetch_list]  # 并行处理所有翻页的页面
    pages = await asyncio.gather(*tasks)
    # 并发 运行 aws 序列中的 可等待对象。
    # 如果 aws 中的某个可等待对象为协程,它将自动作为一个任务加入日程。
    # 如果所有可等待对象都成功完成,结果将是一个由所有返回值聚合而成的列表。结果值的顺序与 aws 中可等待对象的顺序一致。
    for page in pages:
        html = etree.HTML(page)
        for element_movie in html.xpath(xpath_movie):
            result.append(element_movie)

    for i, movie in enumerate(result, 1):
        title = movie.find(xpath_title).text
        desc = (
            "<" + movie.find(xpath_descs).text + ">"
            if movie.find(xpath_descs) is not None
            else None
        )
        link = movie.find(xpath_links).get("href")
        print(i, title, desc, link)


async def main():
    start = time()
    for i in range(5):
        await parse(url)
    end = time()
    print("Cost {} seconds".format((end - start) / 5))


if __name__ == "__main__":
    asyncio.run(main())

Artículo de referencia

  1. De 0 a 1, la evolución del pitón de la trayectoria de la programación asincrónica
  2. Python3 asíncrono / explicación Await
  3. Los documentos oficiales y co-rutina de tareas
Publicado 34 artículos originales · elogios ganado 13 · Vistas a 50000 +

Supongo que te gusta

Origin blog.csdn.net/frone/article/details/89231000
Recomendado
Clasificación