2017-07-03 1 views
3

In meinem Handler async möchte ich warten, bis sich der Status der Aufgabe geändert hat. Im Moment überprüfe ich einfach den Zustand in einer Endlosschleife und warte. Hier ist ein Beispiel, die wait_until_done Funktion:So warten Sie, bis das Objekt den Status ändert

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() 

Gibt es eine bessere Art und Weise, dass zu tun?

+1

Observer-Muster ist wahrscheinlich das, was Sie verwenden möchten. Machen Sie das Objekt "beobachtbar". Dann registrieren Sie einen Handler als Beobachter für Ihr Objekt. Wenn sich der Status ändert, wird er die Methode aufrufen, die Sie wollen. https://stackoverflow.com/questions/1904351/python-observer-pattern-examples- tips – Rob

Antwort

3

Nur um Verwirrung zu vermeiden: Ich denke, Sie sprechen nicht über asyncio.Task, aber einige variable Zustand stattdessen, nicht wahr?

In diesem Fall haben Sie Future und synchronization primitives, die Ihnen erlaubt, etwas zu warten, das asynchron geändert wurde. Wenn Sie zwischen zwei Zuständen wechseln müssen, ist asyncio.Event wahrscheinlich das, was Sie wollen. Hier ist wenig 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:

Komplexere Beispiel, das LongTask Schnittstelle hält:

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

Ja, die Aufgabe ist ein reguläres Objekt, nicht asyncio.Task. Ich dachte über das Ereignis() nach, aber Ihre Lösung ist nicht geeignet: Kurz gesagt, ich kann die "fertig" -Funktion nicht berühren, sie sollte nur den Status der Aufgabe ändern. –

+0

@SergeyBelash, habe ich ein weiteres Beispiel hinzugefügt, das die Funktion "done" unverändert hält. –

0

Ist es nicht ein Beispiel für Observer Design-Muster? Ich denke, das Observer-Muster kann dieses Problem lösen. In diesem Entwurfsmuster brauchen wir nicht unendlich zu iterieren, um die Änderung zu erkennen, vielmehr informiert die Task selbst, ob sie Änderungen vorgenommen hat. Eine einfache Implementierung könnte sein:

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() 

Ausgang:

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

Ihr Code hat nichts mit asyncio und vor allem mit dem Warten auf Zustandsänderungen zu tun - das war die Hauptfrage für das Thema. –

Verwandte Themen