简体   繁体   中英

Waiting for condition without loop Python

I just created a script which triggers a report from specific API and then loads it into my database. I have already built something that works but I would like to know if there is something a bit more "precise" or efficient without the need of making my script loop over and over again.

My current script is the following:

import time

retry=1
trigger_report(report_id)

while report_id.status() != 'Complete':
    time.sleep(retry * 1.3)
    retry =+ 1

load_report(report_id)

EDIT:

The API doesn't provide with any wait for completion methods, the most it has is an endpoint which returns the status of the job. It is a SOAP API.

While this post doesn't hold any relevance anymore as you said, it' a soap API. But I put the work into it, so I'll post it anyway. :)

To answer your question. I don't see any more efficient methods than polling (aka. looping over and over again)


There are multiple ways to do it.

The first way is implementing some sort of callback that is triggered when the task is completed. It will look something like this:

import time

def expensive_operation(callback):
    time.sleep(20)
    callback(6)

expensive_operation(lambda x:print("Done", x))

As you can see, the Message " Done 6 " will be printed as soon as the operation has been completed.

You can rewrite this with Future-objects.

from concurrent.futures import Future
import threading
import time

def expensive_operation_impl():
    time.sleep(20)
    return 6

def expensive_operation():
    fut = Future()
    def _op_wrapper():
        try:
            result = expensive_operation_impl()
        except Exception as e:
            fut.set_exception(e)
        else:
            fut.set_result(result)

    thr = threading.Thread(target=_op_wrapper)
    thr.start()

    return fut

future = expensive_operation()
print(future.result())               # Will block until the operation is done.

Since this looks complicated, there are some high-level functions implementing thread scheduling for you.

import concurrent.futures import ThreadPoolExecutor
import time

def expensive_operation():
    time.sleep(20)
    return 6

executor = ThreadPoolExecutor(1)
future = executor.submit(expensive_operation)

print(future.result())

Rather use events, not polling. There are a lot of options for how to implement events in Python. There was a discussion here already on stack overflow .

Here is a synthetic example uses zope.event and an event handler

import zope.event
import time


def trigger_report(report_id):
    #do expensive operation like SOAP call
    print('start expensive operation')
    time.sleep(5)
    print('5 seconds later...')
    zope.event.notify('Success') #triggers 'replied' function

def replied(event): #this is the event handler
    #event contains the text 'Success'
    print(event)

def calling_function():
    zope.event.subscribers.append(replied)
    trigger_report('1')

But futures as in accepted answer is also neat. Depends on what floats your boat.

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