Наивная реализация обратного вызова: как остановить рост стека? - PullRequest
0 голосов
/ 11 октября 2019

Я только что узнал о концепции обратных вызовов, я решил попробовать реализовать свою собственную. Мои усилия были плодотворными, мне действительно удалось смоделировать функциональность обратного вызова. К сожалению, я заметил, что моя реализация привела к увеличению стека на 2 вызова функции за каждый цикл, что, я полагаю, в конечном итоге приведет к переполнению стека, если код будет выполняться в течение достаточного времени.

Мне было интересноКак я могу реализовать этот код, чтобы предотвратить рост стека на каждом цикле? Или это неизбежный продукт этой реализации, и как в таком случае обойти эту проблему?

import time
import inspect 

def doSomething(x):
    return x + 0.00000001

def continue_processing(runningTotal,termination_condition,callback,callback_args,timeout=5):
    startTime = time.time()
    while (time.time() - startTime < timeout and not(termination_condition(runningTotal))):
        runningTotal = doSomething(runningTotal)

    print(f"Returning control to calling function, running total is {runningTotal}")
    return callback(runningTotal,*callback_args)

def process(runningTotal,n,beginTime):

    if(runningTotal < n):
        print(f"Continue processing, running total is {runningTotal}\nTime elapsed {time.time() - beginTime}\nCurrent stack size: {len(inspect.stack())}")
        continue_processing(runningTotal,lambda x: x>n,process,(n,beginTime))

if __name__ == '__main__':

    beginTime = time.time()
    try:
        process(0,1,beginTime)
    except KeyboardInterrupt:
        print("Program interrupted!")
        exit(0)
    print(f"Completed in {time.time() - beginTime}"

1 Ответ

0 голосов
/ 11 октября 2019

Проблема в том, что обратный вызов рекурсивен, он вызывает себя (косвенно) - вот почему стек переполняется. Ниже описано, как этого избежать. Примечание. Я также изменил ваш код, чтобы он соответствовал PEP 8 - Руководству по стилю для Python Code , чтобы сделать его более читабельным. Я настоятельно рекомендую вам прочитать и следовать ему, особенно если вы только изучаете язык.

import time
import inspect


def doSomething(x):
    return x + 0.00000001

def continue_processing(runningTotal, termination_condition, timeout=5):
    startTime = time.time()
    while (time.time() - startTime < timeout
            and not(termination_condition(runningTotal))):
        runningTotal = doSomething(runningTotal)

    print(f"Returning control to calling function, running total is "
          f"{runningTotal}")

    # Don't call back the callback
    #return callback(runningTotal, *callback_args)

def process(runningTotal, n, beginTime):
    while runningTotal < n:
        print(f"Continue processing, running total is {runningTotal}\n"
              f"Time elapsed {time.time() - beginTime}\n"
              f"Current stack size: {len(inspect.stack())}")
        continue_processing(runningTotal, lambda x: x>n)


if __name__ == '__main__':

    beginTime = time.time()
    try:
        process(0, 1, beginTime)
    except KeyboardInterrupt:
        print("Program interrupted!")
        exit(0)
    print(f"Completed in {time.time() - beginTime}")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...