Python asyncio.Event () в разных классах - PullRequest
1 голос
/ 09 июля 2020

Я пишу программу Python для взаимодействия с устройством на основе CAN-шины. Я успешно использую для этой цели модуль python -can. Я также использую asyncio для реакции на асинхронные события. Я написал класс CanBusManager, который используется классом CanBusSequencer. Класс «CanBusManager» заботится о создании / отправке / получении сообщений, а CanBusSequencer управляет последовательностью отправляемых сообщений. В какой-то момент в последовательности я хочу подождать, пока не будет получено определенное сообщение c, чтобы «разблокировать» остальные сообщения, которые будут отправлены в последовательности. Обзор в коде:

main.py

async def main():
   
   event = asyncio.Event()
   sequencer = CanBusSequencer(event)
   task = asyncio.create_task(sequencer.doSequence())
   await task
 
asyncio.run(main(), debug=True)

canBusSequencer.py

from canBusManager import CanBusManager

class CanBusSequencer:
 
   def __init__(self, event)
 
      self.event = event
      self.canManager = CanBusManager(event)

   async def doSequence(self):
 
      for index, row in self.df_sequence.iterrows():
         if:...
            self.canManager.sendMsg(...)
         else:
            self.canManager.sendMsg(...)
            await self.event.wait()
            self.event.clear()

canBusManager.py

import can

class CanBusManager():
 
   def __init__(self, event):
 
      self.event = event
      self.startListening()
 
 **EDIT**
    def startListening(self):
    
       self.msgNotifier = can.Notifier(self.canBus, self.receivedMsgCallback)
 **EDIT**
 
   def receivedMsgCallback(self, msg):
 
      if(msg == ...):
         self.event.set()
   

На данный момент моя программа остается на await self.event.wait (), даже если соответствующее сообщение получено и выполняется self.event.set (). Запуск программы с debug = True показывает

RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one

, которого я действительно не понимаю. Это связано с событием asyncio l oop, каким-то образом неправильно определенным / управляемым. Я пришел из мира C ++ и в настоящее время пишу свою первую большую программу с Python. Любое руководство было бы очень признательно :)

1 Ответ

0 голосов
/ 09 июля 2020

В вашем вопросе не объясняется, как вы организуете вызов receivedMsgCallback.

Если он вызывается классическим c "asyn c" API, который использует потоки за кулисами, тогда он будет вызываться извне потока, который запускает событие l oop. Согласно документации , примитивы asyncio не потокобезопасны , поэтому вызов event.set() из другого потока не синхронизируется должным образом с запущенным событием l oop, поэтому ваша программа не просыпается, когда должна.

Если вы хотите сделать что-либо, связанное с asyncio, например вызвать Event.set, извне потока событий l oop, вам нужно использовать call_soon_threadsafe или аналогичный. Например:

    def receivedMsgCallback(self, msg):
        if msg == ...:
            self.loop.call_soon_threadsafe(self.event.set)

Объект события l oop должен быть доступен для объекта CanBusManager, возможно, путем передачи его конструктору и присвоения self.loop.

Кстати, если вы создаете задачу только для немедленного ее ожидания, вам вообще не нужна задача. Другими словами, вы можете заменить task = asyncio.create_task(sequencer.doSequence()); await task на более простой await sequencer.doSequence().

...