Как остановить гиперопеку в середине (или до) ее вычисления? — Python

#python #timeout #calculation

#python #тайм-аут #вычисление

Вопрос:

В настоящее время я работаю над переводом множества математических функций на python для использования для счетного бота в discord (поскольку наш текущий счетный бот не имеет абсолютно никакой забавной математики!).

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

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

Например:

 def knuth(a,n,b):
try:
    if b == 0:
        return 1
    if n == 1:
        return a**b
    return knuth(a, n-1, knuth(a,n,b-1))
except KeyboardInterrupt:
    print("Your number is too big yo!")
    exit()
#for example knuth(5,2,5) = 5**5**5**5**5 <- I really don't want to calculate anything that big.
 

Я предполагаю, что это очень распространенная проблема среди тех, кто занимается математикой на python, но все мои поиски привели к способам реализации тайм-аута, который, похоже, не помогает. Есть ли способ обнаружить, что вот-вот произойдет сверхмассивное вычисление, и остановить его до того, как это произойдет?

Ответ №1:

Это интересный вопрос

Вы можете настроить проверку следующим образом: просто выберите свой допуск

 tolerance = 10000000000000
def knuth(a,n,b):
    try:
        if b == 0:
            return 1
        if n == 1:
            return a**b
        if knuth(a, n-1, knuth(a,n,b-1)) > tolerance:
            return 'too big'
        return knuth(a, n-1, knuth(a,n,b-1))
    except KeyboardInterrupt:
        print("Your number is too big yo!")
        exit()
 

Теперь в идеале вы хотели бы автоматически определять, какой допуск, прежде чем он станет слишком большим, и все начнет зависать, но на данный момент указание большого числа является простым решением

Комментарии:

1. Единственная проблема, с которой я сталкиваюсь, заключается в том, что допуск будет улавливаться только в том случае, если вычисление не до такой степени, чтобы оно приводило к сбою python, который трудно ограничить в зависимости от количества реализованных стрелок. Иногда первая итерация может дать 100, а вторая имеет длину 10E 100000 цифр.

Ответ №2:

Хорошо, я думаю, что решил свою собственную проблему, но это очень запутанный обходной путь и, вероятно, содержит действительно плохие методы кодирования…

 import multiprocessing as mp
from queue import Empty #im on python 3 which apparently means queue is lowercased :)  

def knuth(a,n,b):
    if b == 0:
        return 1
    if n == 1:
        return a**b
    return knuth(a, n-1, knuth(a,n,b-1))
    
    def queuebuff(q,a,n,b): #this and def x() were needed for whatever reason for the
    q.put(knuth(a,n,b)) #queue to work, otherwise I would time out... not sure why
                        #couldnt for the life of me get it to work without it.
def x(q,a,n,b):         #Also I was just frustrated, this will get renamed to
    return (q,a,n,b)    #something more meaningful once I figure out what it is doing
                        #and why I need it for the queue to work...
def queue(a,n,b):
    try:
        q=mp.Queue()
        p = mp.Process(target=queuebuff, args=x(q,a,n,b)) #I know I didn't put this
        p.start()                                         #behind a name gate. Wasn't
        Queuedval = q.get(timeout=5)                      #sure what to do if it was.
        while not q.empty(): #this just dumps any other queued items in case something
            q.get(timeout=5) #goes wrong... no clue if this is good practice.
        p.join()
        return Queuedval
    except Empty:
        print('calculation too large stop it!')
        p.kill() #I cant join the process or it will hang so this was my solution. 
        print('multiprocess closed!')
    print('children active: ',mp.active_children()) #check for children and parents
    print('parents active: ',mp.parent_process())   #seems like it works fine ?