1

I am working on a ayncio module and having issues in terminating program. I am running my program in terminal and Ctrl + C is not working to stop the running program.However, if I close the terminal and try to run program again, I get this issue :

INFO:root:In main
ERROR:root:This event loop is already running

Below is my sample code for understanding.

# all_tasks.py

import asyncio
import logging
# module imports
import settings

#configure logging into a file
logging.basicConfig(filename=settings.LOG_FILENAME,level=logging.DEBUG)


class AsyncTest(object):

    async def taskOne(self):
        while True:
            print("Task One") # Print is just an example, I am doing lot of stuff inside.
            await asyncio.sleep(60)

    async def taskTwo(self):
        while True:
            print("Task Two") # Print is just an example, I am doing lot of stuff inside.
            await asyncio.sleep(60) 

    async def main(self):
        try:
            loop = asyncio.get_event_loop()
                tasks = [
                        asyncio.ensure_future(self.taskOne()),
                        asyncio.ensure_future(self.taskTwo()),
                        ]
            loop.run_until_complete(asyncio.wait(tasks))
        except RuntimeError as error:
            logging.info("In main")
            logging.error(error)

if __name__ == '__main__':
    asynctest = AsyncTest()
    asyncio.run(asynctest.main())

Config: Windows 10, python 3.7.0

File Name: all_tasks.py

Command: python all_tasks.py

Any help is much appreciated. Thanks

Sumit S Chawla
  • 3,180
  • 1
  • 14
  • 33

1 Answers1

1

asyncio.run creates and runs event loop. You shouldn't create and run one, especially inside a coroutine (function defined with async def). In a coroutine you should only await for something.

Modify the code accordingly:

# ...

    async def main(self):
        tasks = [
            asyncio.ensure_future(self.taskOne()),
            asyncio.ensure_future(self.taskTwo()),
        ]
        await asyncio.wait(tasks)

if __name__ == '__main__':
    asynctest = AsyncTest()
    asyncio.run(asynctest.main())

It'll work.

Mikhail Gerasimov
  • 36,989
  • 16
  • 116
  • 159
  • Thanks @mikhail, it worked. Also, Is there any good article on understanding asyncio in python. I found few online, but they are mainly on abstract level. – Sumit S Chawla Apr 12 '19 at 14:09
  • @Sam you're welcome. Take a look at the [post here](https://stackoverflow.com/a/33399896/1113207), it tries to give overall overview. Feel free to ask if you're interested in something particular. – Mikhail Gerasimov Apr 12 '19 at 14:23
  • what if `taskOne()` has to use `loop. run_until_complete()` to make it a sync function, while `main()` has to be an async function? How can I avoid the error then? – Emerson Xu Dec 30 '19 at 12:45
  • @EmersonXu you shouldn't use `run_until_complete()` inside async functions. Please read [this answer](https://stackoverflow.com/a/56525798/1113207) for more details. – Mikhail Gerasimov Dec 30 '19 at 13:30
  • @MikhailGerasimov what if that's the legacy code and all other layers of functions are sync functions, and we want to minimize the code change, what should we do? – Emerson Xu Dec 30 '19 at 19:41
  • 1
    @EmersonXu most high-level legacy functions that should be sync can be run asynchronously in thread using [run_in_executor](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor). It is [a common way](https://stackoverflow.com/a/51051980/1113207) to cast some sync function you can't rewrite to async coroutine. But after all this, in the end, on very top of the final program should be single event loop that runs some top-level coroutine. – Mikhail Gerasimov Dec 31 '19 at 04:27