Python3.6 cocotb coroutine: llamar a una función asincrónica que contiene “yield” en una función sincrónica.
Me encontré con algunos problemas al intentar hacer una función síncrona que llama a funciones asíncronas. (Python 3.6.9, cocotb 1.4.0)
Como se muestra en el siguiente código de ejemplo, la función “read_cb” llamará a la función “read” (en la clase “FakeDriver”).
Después de ejecutarlo, obtengo el error:
yield self._fake_lock()
RuntimeError: Task got bad yield: <cocotb.decorators.runningcoroutine object="" at="" 0x7f7fecdbfe10="">
Lo que quiero es:
init FakerDriver
bloqueando...
bloqueo completado
leer...
dirección: 0x01
desbloqueando...
desbloqueo completado
lectura completada
import cocotb
import asyncio
from cocotb.decorators import coroutine
from cocotb.triggers import Event
class FakeDriver():
def __init__(self):
print("init FakeDriver")
self.busy_event = Event("driver_busy")
self.busy = False
@coroutine
def read(self, addr):
print("leer...")
yield self._fake_lock()
print("dirección:", addr)
self._fake_unlock()
print("lectura completada")
@coroutine
def _fake_lock(self):
print("bloqueando...")
if self.busy:
yield self.busy_event.wait()
self.busy_event.clear()
self.busy = True
print("bloqueo completado")
def _fake_unlock(self):
print("desbloqueando...")
self.busy = False
self.busy_event.set()
print("desbloqueo completado")
def read_cb():
dri = FakeDriver()
loop = asyncio.get_event_loop()
task = loop.create_task(dri.read("0x01"))
ret = loop.run_until_complete(task)
loop.close()
if __name__ == "__main__":
read_cb()
</cocotb.decorators.runningcoroutine>
davy.ai
El problema con el código proporcionado es que
read_cb
es una función síncrona que llama a una función asíncrona_fake_lock
que utiliza la palabra claveyield
para suspender la ejecución de la corutina hasta que se resuelva un futuro.Para llamar a una función asíncrona desde una función síncrona, necesitamos utilizar la función asyncio.run(), que es la encargada de ejecutar un bucle de eventos.
Entonces, la función
read_cb
necesita ser modificada de la siguiente manera:Observa que ya no es necesario crear y cerrar el bucle de eventos, ya que
asyncio.run()
se encarga de eso.Esta modificación debería permitir que se imprima la salida esperada: