Running functions in a thread class in the background with asyncio

This is my first attempt at using asyncio in a project. I'd like my class to initialize and run, with several of its functions running periodically "in the background". I'd like the class' init to return after starting these background tasks, so that it can continue to do its synchronous stuff at the same time.

What I have:

 class MyClass(threading.Thread):
  def __init__(self, param):
      self.stoprequest = threading.Event()
      threading.Thread.__init__(self)

      self.param = param

      self.loop = asyncio.new_event_loop()
      asyncio.set_event_loop(self.loop)
      asyncio.ensure_future(self.periodic(), loop=self.loop)

      print("Initialized")

  async def periodic(self):
      while True:
          print("I'm here")
          await asyncio.sleep(1)

  def run(self):
       # continue to do synchronous things

I'm sure unsurprisingly, this doesn't work. I've also tried using a "normal" asyncio function with run_until_complete() in init, but of course init never returns then.

How can I run asyncio functions that belong to this class periodically in the background, while the rest of the class (run()) continues to do synchronous work?

Upvotes: 1

Views: 3819

Answers (1)

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39606

Passing loop as argument to ensure_future doesn't start this loop. You should call run_until_complete or run_forever to force you coroutines being started, there's no other way to do it.

How can I run asyncio functions that belong to this class periodically in the background, while the rest of the class (run()) continues to do synchronous work?

You can't. Just as you can't run event loop and synchronious code simultaneously in the main thread. Loop starting - blocks thread's execution flow until loop is stopped. This is just how asyncio works.

If you want to run asyncio in background you should run it in separate thread and do your synchronous things in main thread. Example of how to do it can be found here.

It you need to run blocking code in thread alongside with asyncio most convenient way now is to run asyncio in the main thread and to run blocking code in a background thread using run_in_executor function. You can find example of doing it here.

It's important to say that asyncio itself usually is used in main thread (without other threads) to achieve benefits of asynchronous programming. Are you sure you need second thread? If not please read this answer to see why asyncio is used.

Upvotes: 3

Related Questions