Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

161
Visualizações
¿Cómo funciona realmente asyncio?

Esta pregunta está motivada por mi otra pregunta: ¿Cómo esperar en cdef?

Hay toneladas de artículos y publicaciones de blog en la web sobre asyncio , pero todos son muy superficiales. No pude encontrar ninguna información sobre cómo se implementa realmente asyncio y qué hace que la E/S sea asíncrona. Estaba tratando de leer el código fuente, pero son miles de líneas de código C que no es del más alto grado, muchas de las cuales tratan con objetos auxiliares, pero lo más importante es que es difícil conectar entre la sintaxis de Python y el código C que traduciría. dentro.

La propia documentación de Asyncio es aún menos útil. No hay información allí sobre cómo funciona, solo algunas pautas sobre cómo usarlo, que a veces también son engañosas/muy mal escritas.

Estoy familiarizado con la implementación de rutinas de Go, y esperaba que Python hiciera lo mismo. Si ese fuera el caso, el código que encontré en la publicación vinculada anteriormente habría funcionado. Como no lo hizo, ahora estoy tratando de averiguar por qué. Mi mejor conjetura hasta ahora es la siguiente, corríjame donde me equivoque:

  1. Las definiciones de procedimientos de la forma async def foo(): ... en realidad se interpretan como métodos de una clase que hereda coroutine .
  2. Tal vez, async def en realidad se divide en varios métodos mediante declaraciones de await , donde el objeto, en el que se llama a estos métodos, puede realizar un seguimiento del progreso realizado a través de la ejecución hasta el momento.
  3. Si lo anterior es cierto, entonces, esencialmente, la ejecución de una corrutina se reduce a llamar a los métodos del objeto corrutina por parte de algún administrador global (¿bucle?).
  4. El administrador global es de alguna manera (¿cómo?) consciente de cuándo las operaciones de E/S son realizadas por el código de Python (¿solo?) y puede elegir uno de los métodos de rutina pendientes para ejecutar después de que el método de ejecución actual renuncie al control (presione el botón await declaración).

En otras palabras, aquí está mi intento de "desazucarar" alguna sintaxis asyncio en algo más comprensible:

 async def coro(name): print('before', name) await asyncio.sleep() print('after', name) asyncio.gather(coro('first'), coro('second')) # translated from async def coro(name) class Coro(coroutine): def before(self, name): print('before', name) def after(self, name): print('after', name) def __init__(self, name): self.name = name self.parts = self.before, self.after self.pos = 0 def __call__(): self.parts[self.pos](self.name) self.pos += 1 def done(self): return self.pos == len(self.parts) # translated from asyncio.gather() class AsyncIOManager: def gather(*coros): while not every(c.done() for c in coros): coro = random.choice(coros) coro()

Si mi conjetura resulta correcta: entonces tengo un problema. ¿Cómo ocurre realmente la E/S en este escenario? en un hilo aparte? ¿Se suspende todo el intérprete y la E/S ocurre fuera del intérprete? ¿Qué se entiende exactamente por E/S? Si mi procedimiento de python llamó al procedimiento C open() y, a su vez, envió una interrupción al kernel, cediendo el control, ¿cómo sabe esto el intérprete de Python y puede continuar ejecutando otro código, mientras que el código del kernel hace el I/ real? O y hasta que despierte el procedimiento de Python que envió la interrupción originalmente? ¿Cómo puede el intérprete de Python, en principio, ser consciente de que esto sucede?

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

El desazúcar de tu coro es conceptualmente correcto, pero ligeramente incompleto.

await no suspende incondicionalmente, pero solo si encuentra una llamada de bloqueo. ¿Cómo sabe que una llamada está bloqueando? Esto se decide por el código que se espera. Por ejemplo, una implementación esperable de lectura de socket podría reducirse a:

 def read(sock, n): # sock must be in non-blocking mode try: return sock.recv(n) except EWOULDBLOCK: event_loop.add_reader(sock.fileno, current_task()) return SUSPEND

En asyncio real, el código equivalente modifica el estado de un Future en lugar de devolver valores mágicos, pero el concepto es el mismo. Cuando se adapte adecuadamente a un objeto similar a un generador, se puede await el código anterior.

En el lado de la persona que llama, cuando su rutina contiene:

 data = await read(sock, 1024)

Se desazucara en algo parecido a:

 data = read(sock, 1024) if data is SUSPEND: return SUSPEND self.pos += 1 self.parts[self.pos](...)

Las personas familiarizadas con los generadores tienden a describir lo anterior en términos de yield from cual se produce la suspensión de forma automática.

La cadena de suspensión continúa hasta el bucle de eventos, que detecta que la rutina está suspendida, la elimina del conjunto ejecutable y ejecuta las rutinas ejecutables, si las hay. Si no se pueden ejecutar corrutinas, el ciclo espera en select() hasta que un descriptor de archivo en el que está interesada una corrutina esté listo para IO o expire el tiempo de espera. (El bucle de eventos mantiene una asignación de descriptor de archivo a corrutina).

En el ejemplo anterior, una vez que select() le dice al ciclo de eventos que sock es legible, volverá a agregar coro al conjunto ejecutable, por lo que continuará desde el punto de suspensión.

En otras palabras:

  1. Todo sucede en el mismo hilo por defecto.

  2. El bucle de eventos es responsable de programar las corrutinas y despertarlas cuando lo que sea que estaban esperando (por lo general, una llamada de E/S que normalmente se bloquearía o un tiempo de espera) esté lista.

Para obtener información sobre los bucles de eventos que impulsan la corrutina, recomiendo esta charla de Dave Beazley, donde demuestra cómo codificar un bucle de eventos desde cero frente a una audiencia en vivo.

over 4 years ago · Santiago Trujillo Relatório

0

Le permite escribir código asíncrono de subproceso único e implementar la concurrencia en Python. Básicamente, asyncio proporciona un bucle de eventos para la programación asincrónica. Por ejemplo, si necesitamos realizar solicitudes sin bloquear el hilo principal, podemos usar la biblioteca asyncio .

El módulo asyncio permite la implementación de programación asíncrona utilizando una combinación de los siguientes elementos:

  • Bucle de eventos: El módulo asyncio permite un bucle de eventos por proceso.

  • Corrutinas: Una corrutina es un generador que sigue ciertas convenciones. Su característica más interesante es que puede suspenderse durante la ejecución para esperar el procesamiento externo (alguna rutina en E/S) y regresar desde el punto en que se detuvo cuando se realizó el procesamiento externo.

  • Futuros: Los futuros representan un proceso que aún no ha terminado. Un futuro es un objeto que se supone que tiene un resultado en el futuro y representa tareas incompletas.

  • Tareas: esta es una subclase de asyncio .Future que encapsula y administra rutinas. Podemos usar el objeto asyncio.Task para encapsular una rutina.

El concepto más importante dentro de asyncio es el bucle de eventos. Un bucle de eventos le permite escribir código asincrónico utilizando devoluciones de llamada o corrutinas. Las claves para comprender asyncio son los términos de las rutinas y el bucle de eventos. Las corrutinas son funciones con estado cuya ejecución se puede detener mientras se ejecuta otra operación de E/S. Se utiliza un bucle de eventos para orquestar la ejecución de las corrutinas.

Para ejecutar cualquier función de rutina, necesitamos obtener un bucle de eventos. Podemos hacer esto con

 loop = asyncio.get_event_loop()

Esto nos da un objeto BaseEventLoop . Esto tiene un método run_until_complete que toma una rutina y la ejecuta hasta que finaliza. Luego, la rutina devuelve un resultado. En un nivel bajo, un bucle de eventos ejecuta el BaseEventLoop.rununtilcomplete(future) .

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda