В Python выход из блокировки в DatagramProtocol.datagram_received делает функцию никогда не вызываемой
Я хочу синхронизировать данные между сопрограммами, и в итоге получаю метод, который не вызывается, когда в нем есть "yield".
Чтобы быть более точным, когда я реализую класс DatagramProtocol с методом datagram_received согласно документу ( вдохновленный этим), все работает нормально, я получаю данные. Как только я добавляю "yield" в метод datagram_received, метод больше не вызывается. Вот пример:
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()
Как метод может внезапно перестать вызываться в зависимости от содержимого метода?
Что мне не хватает? Как сделать синхронизацию?
1 ответ
Что мне не хватает?
Документация, которая вдохновила вас, также гласит:
Сопрограммы могут быть запланированы в методе протокола с использованием sure_future(), но нет никакой гарантии относительно порядка выполнения. Протоколы не знают о сопрограммах, созданных в методах протокола, и поэтому не будут ждать их.
Чтобы иметь надежный порядок выполнения, используйте потоковые объекты в сопрограмме с yield from. Например, сопрограмму StreamWriter.drain() можно использовать для ожидания очистки буфера записи.
Ты не можешь yield from
/await
внутри datagram_received
, ты можешь:
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()
Как метод может внезапно перестать вызываться в зависимости от содержимого метода?
Использование yield
или же yield from
в функции, делает его генератором. Так datagram_received
возвращает объект генератора. Чтобы фактически выполнить код (до выхода), вы должны использовать 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/