简体   繁体   中英

How do I exit a recursive DFS algorithm after a certain time in python?

I have a recursive depth first search function in python that I want to exit completely from (the entire stack) after a certain time. The recursive function is aware of the time remaining (it's passed a variable called time_remaining), and when this time_remaining is less than say 100 ms, I want to exit out of the entire recursion stack, and return some default values. What's the best way to accomplish this in python?

Here is one way to do this. It uses an exception to unwind the stack, and a decorator to check the time remaining at each call to the recursion.

import time

class TimeRemainingExpired(Exception):
    pass

def enforce_time_remaining(f):
    """ decorator to check time remaining and raise if expired """
    def new_f(*args, **kwargs):
        if kwargs.get('_time_remaining_end_time') is None:
            kwargs['_time_remaining_end_time'] = \
                time.time() + kwargs['time_remaining']
            print(kwargs['_time_remaining_end_time'])
            print(kwargs['time_remaining'])
        if time.time() >= kwargs['_time_remaining_end_time']:
            raise TimeRemainingExpired
        return f(*args, **kwargs)

    return new_f


@enforce_time_remaining
def recurse(**kwargs):
    time.sleep(.01)
    recurse(**kwargs)

print(time.time())
try:
    recurse(time_remaining=1)
except TimeRemainingExpired:
    print('Time Expired')
print(time.time())

Essentially, you need to start a thread to stop a global time variable after a set allocated amount of time, then allow your search function to run afterwards and check when that max time condition is false or in some state that tells you the program is no longer suppose to recursively continue.

This is an example of a recursive function, I've passed in an iteration so you can see it go and artificially slowed it down. You need to start a thread to start a global timer, then check that global timer each time you call the recursive function.

import time
from threading import Thread

# create a global variable time that is ture
global_time = True 

# start the timer
def start_timer():
        time.sleep(0.1) # 1/10 second
        # Make sure you're referencing the GLOBAL time variable.
        global global_time
        # After 1/10 second, the timer will stop.
        global_time = False
        print("time stopped")

# The itteration variable is just for display.
def dfs(itteration):
        # Put your search logic here.

        # Again, make sure you're referencing the GLOBAL time variable.
        global global_time
        if global_time == True:
                # Artificially slowing down the search function.
                time.sleep(0.01)
                # Just print the iteration so you can see what's going on.
                itteration = itteration + 1 
                print(itteration)
                return dfs(itteration)
        else:
                return "DONE"

# First start the timer.
timer_thread = Thread(target = start_timer)
timer_thread.start()
# Run the search function.
print(dfs(0))

Since the timer is 1/10 second until it's false and each itteration will take 1/100, it should only run 10 times. This is my result:

python time.py 
1
2
3
4
5
6
7
8
9
time stopped
DONE

It's important that you use global or sle the dfs function will not know that global_time is the one you set on line 4 and it will go on forever.

Note my python version is 3.5 and threading may be different in the 2.7 version.

Unrelated note: DFS is terribly inefficient. You should be using BFS ( Breadth first search ) or A* search (which is proven to be optimal ), although this is not related to the question.

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