简体   繁体   English

如何在没有名称的异步中停止无限事件循环?

[英]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.它将 display.exit 更改为 True 并结束循环。

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!我可以进行键盘中断,但是每当我尝试使用 asyncio.run() 运行另一个任务时,我都会收到一条错误消息,指出无法从正在运行的事件循环中调用 asyncio.run()!

How do I close this active loop so that I can use asyncio.run() again??!!!如何关闭这个活动循环,以便我可以再次使用 asyncio.run() ??!!!

I am working in a Jupyter Notebook, if this is relevant.如果这是相关的,我正在使用 Jupyter Notebook。

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.当我运行此代码时,它似乎导致 Python “忘记”所有早期的 asyncio.run() 命令,现在我可以使用 asyncio.run() 正常运行其他代码块。

Your class has no errors.您的 class 没有错误。 The error is the way you're using run() method.错误是您使用run()方法的方式。

When you execute asyncio.run(display.start()) the program will wait to that coroutine to finish.当您执行asyncio.run(display.start())时,程序将等待该协程完成。 So, in this case you're runing display.start() that is an infinite loop.因此,在这种情况下,您正在运行display.start()这是一个无限循环。 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.您必须在asyncio.run()中调用一个管理所有指令的协程。 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: 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您提供的解决方案有效,但这根本不是推荐的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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