在 Python 中,yield from lock in DatagramProtocol.datagram_received 使得该函数从未被调用

In Python, yielding from lock in DatagramProtocol.datagram_received makes the function never called

我想在协同程序之间同步数据,但我最终得到了一个方法,只要其中有 "yield" 就不会被调用。

更准确地说,当我根据文档 (inspired from this) 使用方法 datagram_received 实现 DatagramProtocol class 时,一切正常,我收到了数据。只要我在方法 datagram_received 中添加 "yield",就再也不会调用该方法。这是一个例子:

loop = asyncio.get_event_loop()
lock = asyncio.Lock(loop=loop)

class MyProtocol(asyncio.DatagramProtocol):
    def datagram_received(self, data, addr):
        global my_data, lock
        print("here")
        # uncomment the following lines and datagram_received is 
        # not called at all (never see the "here" on the console)
        #yield from lock
        #try:
        #    my_data = float(data.decode())
        #finally:
        #    lock.release()

loop.run_until_complete(loop.create_datagram_endpoint(MyProtocol, sock=create_socket(10000)))

loop.run_forever()

一个方法怎么会突然不被调用取决于方法的内容?

我错过了什么?应该如何同步?

我错过了什么?

启发您的文档还指出:

Coroutines can be scheduled in a protocol method using ensure_future(), but there is no guarantee made about the execution order. Protocols are not aware of coroutines created in protocol methods and so will not wait for them.

To have a reliable execution order, use stream objects in a coroutine with yield from. For example, the StreamWriter.drain() coroutine can be used to wait until the write buffer is flushed.

您不能在 datagram_receivedyield from/await,您可以:

class MyProtocol(asyncio.DatagramProtocol):
    def datagram_received(self, data, addr):
        global my_data, lock
        print("here")
        loop.ensure_future(some_function())
        
    @asyncio.coroutine
    def some_function(self):
        yield from lock
        try:
            my_data = float(data.decode())
        finally:
            lock.release()

一个方法怎么会突然不被调用取决于方法的内容?

在函数中使用 yieldyield from 使其成为生成器。所以 datagram_received returns 生成器对象。要实际执行代码(直到 yield),您应该使用 next,asyncio 使用(基于生成器的)协程执行它(但同样 datagram_received 不是一个)

>>> def test():
...     print('test')
...     yield from 'A'
... 
>>> test()
<generator object test at 0x7f4165d42fc0>
>>> next(test())
test
'A'

关于生成器的更多信息:https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/