如何等待对象改变状态

如何等待对象改变状态

问题描述:

在我的async处理程序内我想等到任务的状态改变。现在,我只是无休止地检查状态并等待。下面是一个例子,wait_until_done功能:如何等待对象改变状态

import asyncio 


class LongTask: 
    state = 'PENDING' 

my_task = LongTask() 


def done(): 
    my_task.state = 'DONE' 

async def wait_until_done(): 
    while True: 
     if my_task.state == 'PENDING': 
      await asyncio.sleep(2) 
     else: 
      break 
    print("Finally, the task is done") 


def main(loop, *args, **kwargs): 
    asyncio.ensure_future(wait_until_done()) 
    loop.call_later(delay=5, callback=done) 

loop = asyncio.get_event_loop() 
main(loop) 
loop.run_forever() 

是否有这样做的更好的办法?

+1

Observer模式可能是你想要使用什么。使对象“可观察”,然后注册一个处理程序作为对象的一个​​处理程序,所以当状态改变时它将调用你想要的任何方法。 https://*.com/questions/1904351/python-observer-pattern-examples-tips – Rob

只是为了避免混淆:我猜你不是在谈论asyncio.Task,而是一些可变的状态,对吗?

在这种情况下,您有Futuresynchronization primitives,它允许您等待某些异步更改的内容。

如果您需要在两种状态之间切换,asyncio.Event可能是您想要的。这里的小examle:

import asyncio 


my_task = asyncio.Event() 


def done(): 
    my_task.set() 



async def wait_until_done(): 
    await my_task.wait() # await until event would be .set() 
    print("Finally, the task is done") 


async def main(): 
    loop.call_later(delay=5, callback=done) 
    await wait_until_done() 


loop = asyncio.get_event_loop() 
try: 
    loop.run_until_complete(main()) 
finally: 
    loop.run_until_complete(loop.shutdown_asyncgens()) 
    loop.close() 

UPD:

更为复杂的例子,保持LongTask接口:

import asyncio 



class LongTask: 
    _event = asyncio.Event() 

    @property 
    def state(self): 
     return 'PENDING' if not type(self)._event.is_set() else 'DONE' 

    @state.setter 
    def state(self, val): 
     if val == 'PENDING': 
      type(self)._event.clear() 
     elif val == 'DONE': 
      type(self)._event.set() 
     else: 
      raise ValueError('Bad state value.') 

    async def is_done(self): 
     return (await type(self)._event.wait()) 

my_task = LongTask() 


def done(): 
    my_task.state = 'DONE' 



async def wait_until_done(): 
    await my_task.is_done() 
    print("Finally, the task is done") 


async def main(): 
    loop.call_later(delay=5, callback=done) 
    await wait_until_done() 


loop = asyncio.get_event_loop() 
try: 
    loop.run_until_complete(main()) 
finally: 
    loop.run_until_complete(loop.shutdown_asyncgens()) 
    loop.close() 
+0

是的,任务是一个常规的对象,而不是asyncio.Task。我想过Event(),但是你的解决方案并不合适:长话短说,我无法触及'done'函数,它应该改变任务的状态。 –

+0

@SergeyBelash,我增加了另一个保持'done' func不变的例子。 –

是不是Observer设计模式的例子吗?我认为观察者模式可以解决这个问题。在这种设计模式中,我们不需要迭代无限来检测变化,而是任务本身会通知它是否发生了任何变化。一个简单的实现可能是:

class ObservableTask: 
    def __init__(self): 
     self.subscribers = set() 
     self.state = 'PENDING' 

    def subscribe(self, who): 
     self.subscribers.add(who) 

    def unsubscribe(self, who): 
     self.subscribers.discard(who) 

    def dispatch(self, message): 
     for subscriber in self.subscribers: 
      subscriber.update(message) 

    def random_change(self): 
     for count in range(1, 10): 
      if count % 5 == 0: 
       print('Inside task:\tDivisible by 5') 
       self.state = 'DONE' 
       self.dispatch('state: DONE') 


class Observer: 
    def __init__(self): 
     pass 

    def update(self, message): 
     print('Task is changed!\t' + message) 


# Test: 
task = ObservableTask() 
observer = Observer() 

task.subscribe(observer) 
task.random_change() 

输出:

Inside task: Divisible by 5 
Task is changed! state: DONE 
+2

您的代码与asyncio无关,特别是在等待状态更改时 - 这是该主题的主要问题。 –