Python рекурсия шегін тексеріңіз және өзгертіңіз (мысалы, sys.setrecursionlimit)

Іскерлік

Python тілінде рекурсиялар санының жоғарғы шегі бар (рекурсиялардың максималды саны). Шақырулар саны көп рекурсивті функцияны орындау үшін шекті өзгерту қажет. Стандартты кітапхананың sys модуліндегі функцияларды пайдаланыңыз.

Рекурсиялар саны стек өлшемімен де шектеледі. Кейбір орталарда стандартты кітапхананың ресурс модулін максималды стек өлшемін өзгерту үшін пайдалануға болады (ол Ubuntu жүйесінде жұмыс істеді, бірақ Windows немесе Mac жүйесінде емес).

Мұнда келесі ақпарат берілген.

  • Ағымдағы рекурсиялар санының жоғарғы шегін алыңыз:sys.getrecursionlimit()
  • Рекурсиялар санының жоғарғы шегін өзгертіңіз:sys.setrecursionlimit()
  • Стектің максималды өлшемін өзгертіңіз:resource.setrlimit()

Үлгі коды Ubuntu жүйесінде жұмыс істейді.

Ағымдағы рекурсия шегін алыңыз: sys.getrecursionlimit()

Ағымдағы рекурсия шегін sys.getrecursionlimit() арқылы алуға болады.

import sys
import resource

print(sys.getrecursionlimit())
# 1000

Мысалда рекурсиялардың максималды саны 1000 болып табылады, ол ортаңызға байланысты өзгеруі мүмкін. Мұнда импортталатын ресурс Windows жүйесінде емес, кейінірек пайдаланылатынын ескеріңіз.

Мысал ретінде біз келесі қарапайым рекурсивті функцияны қолданамыз. Егер аргумент ретінде n оң бүтін саны көрсетілсе, шақырулар саны n есе болады.

def recu_test(n):
    if n == 1:
        print('Finish')
        return
    recu_test(n - 1)

Рекурсияны жоғарғы шектен артық орындауға әрекеттенсеңіз, қате (RecursionError) көтеріледі.

recu_test(950)
# Finish

# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison

sys.getrecursionlimit() арқылы алынған мән қатаң түрде рекурсиялардың максималды саны емес, Python интерпретаторының максималды стек тереңдігі екенін ескеріңіз, сондықтан рекурсиялар саны осы мәннен сәл аз болса да, қате (RecursionError) пайда болады. көтерілу.

再帰限界は、再帰の限界ではなく、pythonインタープリタのスタックの最大の最大
python – Max recursion is not exactly what sys.getrecursionlimit() claims. How come? – Stack Overflow

# recu_test(995)
# RecursionError: maximum recursion depth exceeded while calling a Python object

Рекурсия шегін өзгерту: sys.setrecursionlimit()

Рекурсиялар санының жоғарғы шегін sys.setrecursionlimit() арқылы өзгертуге болады. Жоғарғы шек аргумент ретінде көрсетіледі.

Тереңірек рекурсияны орындауға мүмкіндік береді.

sys.setrecursionlimit(2000)

print(sys.getrecursionlimit())
# 2000

recu_test(1500)
# Finish

Көрсетілген жоғарғы шек тым аз немесе тым үлкен болса, қате орын алады. Бұл шектеу (шектің жоғарғы және төменгі шегі) қоршаған ортаға байланысты өзгереді.

Шектеудің максималды мәні платформаға байланысты. Егер сізге терең рекурсия қажет болса, платформа қолдайтын ауқымда үлкенірек мәнді көрсетуге болады, бірақ бұл мән тым үлкен болса, апатқа әкелетінін ескеріңіз.
If the new limit is too low at the current recursion depth, a RecursionError exception is raised.
sys.setrecursionlimit() — System-specific parameters and functions — Python 3.10.0 Documentation

sys.setrecursionlimit(4)
print(sys.getrecursionlimit())
# 4

# sys.setrecursionlimit(3)
# RecursionError: cannot set the recursion limit to 3 at the recursion depth 1: the limit is too low

sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000

# sys.setrecursionlimit(10 ** 10)
# OverflowError: signed integer is greater than maximum

Рекурсиялардың максималды саны да келесі түсіндірілгендей стек өлшемімен шектеледі.

Стектің максималды өлшемін өзгертіңіз: resource.setrlimit()

Тіпті sys.setrecursionlimit() ішінде үлкен мән орнатылған болса да, рекурсиялар саны көп болса, ол орындалмауы мүмкін. Сегменттеу қатесі келесідей орын алады.

sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish

# recu_test(10 ** 5)
# Segmentation fault

Python тілінде стандартты кітапханадағы ресурс модулін максималды стек өлшемін өзгерту үшін пайдалануға болады. Дегенмен, ресурс модулі Unix үшін арнайы модуль болып табылады және оны Windows жүйесінде пайдалану мүмкін емес.

resource.getrlimit() арқылы аргументте көрсетілген ресурс шегін (жұмсақ шек, қатаң шектеу) кортежі ретінде алуға болады. Мұнда біз ресурс ретінде ресурс.RLIMIT_STACK көрсетеміз, ол ағымдағы процестің шақыру стекінің ең үлкен өлшемін көрсетеді.

print(resource.getrlimit(resource.RLIMIT_STACK))
# (8388608, -1)

Мысалда жұмсақ шектеу 8388608 (8388608 B = 8192 КБ = 8 МБ) және қатаң шектеу -1 (шексіз).

Ресурс шегін resource.setrlimit() арқылы өзгертуге болады. Мұнда жұмсақ шектеу де -1 (шектеусіз) мәніне орнатылған. Сондай-ақ, шектеусіз шектеуді көрсету үшін тұрақты ресурс.RLIM_INFINIT пайдалануға болады.

Стек өлшемі өзгергенге дейін сегменттеу қателігіне байланысты орындалмайтын терең рекурсия енді орындалуы мүмкін.

resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))

print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)

recu_test(10 ** 5)
# Finish

Мұнда жұмсақ шек қарапайым эксперимент үшін -1 (шексіз) мәніне орнатылған, бірақ шын мәнінде оны сәйкес мәнге шектеу қауіпсіз болар еді.

Сонымен қатар, мен Mac компьютерімде де шектеусіз жұмсақ шектеу орнатуға тырысқанда, келесі қате орын алды.ValueError: not allowed to raise maximum limit
Сценарийді sudo көмегімен іске қосу көмектеспеді. Ол жүйемен шектелуі мүмкін.

Суперпайдаланушының тиімді UID идентификаторы бар процесс кез келген ақылға қонымды шектеуді, соның ішінде шектеуді сұрай алады.
Дегенмен, жүйе жүктеген шектеуден асатын сұрау бәрібір ValueError нәтижесіне әкеледі.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows жүйесінде ресурс модулі жоқ және жүйе шектеулеріне байланысты Mac жүйесінде максималды стек өлшемін өзгерте алмады. Егер біз стек өлшемін қандай да бір жолмен ұлғайта алсақ, сегменттеу ақауын шеше алуымыз керек, бірақ біз мұны растай алмадық.

Copied title and URL