简体   繁体   中英

How to stop an infinite event loop in asyncio with no name?

I have the following code:

import asyncio
import time

class displayName:
    def __init__(self, name, delay, exit = False):
        self.name = name
        self.delay = delay
        self.exit = exit
    async def start(self):
        #displays name of object at regular time intervals
        self.exit = False
        print('starting display program...')
        while True:
            if self.exit == True:
                print('ending display program')
                break
            print(self.name)
            await asyncio.sleep(self.delay)
    async def stop(self):
        await asyncio.sleep(0)
        self.exit = True
    async def update_name(self, name):
        await asyncio.sleep(0)
        self.name = name
    async def update_delay(self, delay):
        await asyncio.sleep(0)
        self.delay = delay

Normally, I would execute:

display = displayName('Tom',5)
loop = asyncio.get_event_loop()
loop.create_task(display.start())

and if I wanted to change the name being displayed I would execute:

loop.create_task(display.update_name('Jerry'))

and to stop the loop I would execute:

loop.create_task(display.stop())

which changes display.exit to True and ends the loop.

However, if I attempt to execute this code using:

asyncio.run(display.start())

then I cannot get the loop to close!

I've tried:

loop1 = asyncio.get_running_loop()
loop1.close()

and this did nothing. I can do a keyboard interrupt, but any time I try to run another task with asyncio.run(), I get an error message saying that asyncio.run() cannot be called from a running event loop!

How do I close this active loop so that I can use asyncio.run() again??!!!

I am working in a Jupyter Notebook, if this is relevant.

I scoured the internet and I found the following hack that seems to work:

import nest_asyncio
nest_asyncio.apply()

When I run this code it seems to cause Python to "forget" all the earlier asyncio.run() commands, and now I can use asyncio.run() to run other blocks of code as normal.

Your class has no errors. The error is the way you're using run() method.

When you execute asyncio.run(display.start()) the program will wait to that coroutine to finish. So, in this case you're runing display.start() that is an infinite loop. That's the reason why can't do anything else while that coroutine runs.

You have to call in asyncio.run() a coroutine that manages all the instructions. See the code below:

import asyncio

class displayName:
    def __init__(self, name, delay, exit = False):
        self.name = name
        self.delay = delay
        self.exit = exit
    async def start(self):
        #displays name of object at regular time intervals
        self.exit = False
        print('starting display program...')
        while True:
            if self.exit == True:
                print('ending display program')
                break
            print(f'name: {self.name}     delay:{self.delay}')
            await asyncio.sleep(self.delay)
    async def stop(self):
        await asyncio.sleep(0)
        self.exit = True
    async def update_name(self, name):
        await asyncio.sleep(0)
        self.name = name
    async def update_delay(self, delay):
        await asyncio.sleep(0)
        self.delay = delay

async def main():
    x = displayName('Tom', 1) #Create an instance of displayName
    task = asyncio.create_task(x.start()) #Run x.start()
    await asyncio.sleep(3) #waits 3 secs
    await x.update_name('Chris') #Change name
    await asyncio.sleep(3) #waits 3 secs
    await x.update_delay(0.5) #Change delay time
    await asyncio.sleep(3) #waits 3 secs
    await x.stop() #Stop task
    await task #Wait for task to end

asyncio.run(main())
print("This sentence will NOT be executed concurrently...")
print("This will be executed once asyncio.run() is done")

Output:

name: Tom     delay:1
name: Tom     delay:1
name: Tom     delay:1
name: Tom     delay:1
name: Chris     delay:1
name: Chris     delay:1
name: Chris     delay:1
name: Chris     delay:0.5
name: Chris     delay:0.5
name: Chris     delay:0.5
name: Chris     delay:0.5
ending display program
This sentence will NOT be executed concurrently...
This will be executed once asyncio.run() is done

The solution you gave works, but it's not at all the recommended way to do it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM