Python3.6 cocotb协程:在同步函数中调用包含”yield“的异步函数
Python3.6 cocotb coroutine: calling asynchronous function containing ”yield“ in synchronous function
我在尝试制作一个调用异步函数的同步函数时遇到了一些问题。(python 3.6.9,cocotb 1.4.0)
如下例代码所示。 read_cb
函数将调用 read
函数(在 FakeDriver
class 中)。
在运行之后,我得到了错误
yield self._fake_lock()
RuntimeError: Task got bad yield: <cocotb.decorators.RunningCoroutine object at 0x7f7fecdbfe10>
我要的是
init FakerDriver
locking...
locking done
read...
addr: 0x01
unlocking...
unlocking done
read done
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("read...")
yield self._fake_lock()
print("addr: ", addr)
self._fake_unlock()
print("read done")
@coroutine
def _fake_lock(self):
print("locking...")
if self.busy:
yield self.busy_event.wait()
self.busy_event.clear()
self.busy = True
print("locking done")
def _fake_unlock(self):
print("unlocking...")
self.busy = False
self.busy_event.set()
print("unlocking done")
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 自己的协程实现和 asyncio 的实现。
在您的情况下,完全摆脱 asyncio
导入,并使用旧的 cocotb 1.4.0,使用 cocotb 的 fork()
而不是 create_task()
(如 https://docs.cocotb.org/en/v1.4.0/quickstart.html?highlight=fork#parallel-and-sequential-execution 中所述)。
在使用 cocotb 中已弃用的 yield
等创建大量新代码之前,请考虑将 cocotb 升级到 1.6.1 并使用 async def
/await
(同样来自 cocotb
,而不是 asyncio
),而不是 fork()
,使用 start_soon()
(参见 https://docs.cocotb.org/en/v1.6.1/coroutines.html#concurrent-execution and https://www.fossi-foundation.org/2021/10/20/cocotb-1-6-0)。
(我现在看到你也在https://github.com/cocotb/cocotb/issues/2819问过这个)
我在尝试制作一个调用异步函数的同步函数时遇到了一些问题。(python 3.6.9,cocotb 1.4.0)
如下例代码所示。 read_cb
函数将调用 read
函数(在 FakeDriver
class 中)。
在运行之后,我得到了错误
yield self._fake_lock()
RuntimeError: Task got bad yield: <cocotb.decorators.RunningCoroutine object at 0x7f7fecdbfe10>
我要的是
init FakerDriver
locking...
locking done
read...
addr: 0x01
unlocking...
unlocking done
read done
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("read...")
yield self._fake_lock()
print("addr: ", addr)
self._fake_unlock()
print("read done")
@coroutine
def _fake_lock(self):
print("locking...")
if self.busy:
yield self.busy_event.wait()
self.busy_event.clear()
self.busy = True
print("locking done")
def _fake_unlock(self):
print("unlocking...")
self.busy = False
self.busy_event.set()
print("unlocking done")
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 自己的协程实现和 asyncio 的实现。
在您的情况下,完全摆脱 asyncio
导入,并使用旧的 cocotb 1.4.0,使用 cocotb 的 fork()
而不是 create_task()
(如 https://docs.cocotb.org/en/v1.4.0/quickstart.html?highlight=fork#parallel-and-sequential-execution 中所述)。
在使用 cocotb 中已弃用的 yield
等创建大量新代码之前,请考虑将 cocotb 升级到 1.6.1 并使用 async def
/await
(同样来自 cocotb
,而不是 asyncio
),而不是 fork()
,使用 start_soon()
(参见 https://docs.cocotb.org/en/v1.6.1/coroutines.html#concurrent-execution and https://www.fossi-foundation.org/2021/10/20/cocotb-1-6-0)。
(我现在看到你也在https://github.com/cocotb/cocotb/issues/2819问过这个)