Provjerite i promijenite ograničenje rekurzije Pythona (npr. Sys.setrecursionlimit)

Poslovanje

U Pythonu postoji gornja granica broja rekurzija (najveći broj rekurzija). Za izvršavanje rekurzivne funkcije s velikim brojem poziva potrebno je promijeniti ograničenje. Koristite funkcije u sys modulu standardne knjižnice.

Broj rekurzija također je ograničen veličinom snopa. U nekim se okruženjima resursni modul standardne biblioteke može koristiti za promjenu maksimalne veličine steka (radio je na Ubuntuu, ali ne i na sustavu Windows ili Mac).

Ovdje su navedene sljedeće informacije.

  • Dohvatite gornju granicu trenutnog broja rekurzija:sys.getrecursionlimit()
  • Promijenite gornju granicu broja rekurzija:sys.setrecursionlimit()
  • Promijenite najveću veličinu snopa:resource.setrlimit()

Primjer koda je pokrenut na Ubuntuu.

Dohvati trenutačno ograničenje rekurzije: sys.getrecursionlimit ()

Trenutna granica rekurzije može se dobiti pomoću sys.getrecursionlimit ().

import sys
import resource

print(sys.getrecursionlimit())
# 1000

U primjeru je maksimalan broj rekurzija 1000, što može varirati ovisno o vašem okruženju. Napominjemo da će se resursi koje ovdje uvozimo koristiti kasnije, ali ne u sustavu Windows.

Kao primjer, upotrijebit ćemo sljedeću jednostavnu rekurzivnu funkciju. Ako je pozitivan cijeli broj n naveden kao argument, broj poziva bit će n puta.

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

Pogreška (RecursionError) pojavit će se ako pokušate izvesti rekurziju više od gornje granice.

recu_test(950)
# Finish

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

Imajte na umu da vrijednost dobivena pomoću sys.getrecursionlimit () nije strogo najveći mogući broj rekurzija, već najveća dubina stoga Python tumača, pa čak i ako je broj rekurzija nešto manji od ove vrijednosti, pogreška (RecursionError) će biti podignuta.

再 帰 限界 は 、 再 帰 の 限界 で な tho tho 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

Promijeni ograničenje rekurzije: sys.setrecursionlimit ()

Gornja granica broja rekurzija može se promijeniti pomoću sys.setrecursionlimit (). Gornja granica navedena je kao argument.

Omogućuje dublju rekurziju.

sys.setrecursionlimit(2000)

print(sys.getrecursionlimit())
# 2000

recu_test(1500)
# Finish

Ako je navedena gornja granica premala ili prevelika, doći će do pogreške. Ovo ograničenje (gornja i donja granica same granice) varira ovisno o okolišu.

Maksimalna vrijednost ograničenja ovisi o platformi. Ako vam je potrebna duboka rekurzija, možete navesti veću vrijednost unutar raspona koji podržava platforma, ali imajte na umu da će ta vrijednost uzrokovati pad ako je prevelika.
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

Maksimalni broj rekurzija također je ograničen veličinom stoga, kako je dalje objašnjeno.

Promijenite najveću veličinu stoga: resource.setrlimit ()

Čak i ako je velika vrijednost postavljena u sys.setrecursionlimit (), ona se možda neće izvršiti ako je broj rekurzija velik. Do greške segmentacije dolazi na sljedeći način.

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

# recu_test(10 ** 5)
# Segmentation fault

U Pythonu se resursni modul u standardnoj knjižnici može koristiti za promjenu maksimalne veličine stoga. Međutim, resursni modul je Unix-specifičan modul i ne može se koristiti u sustavu Windows.

Pomoću resource.getrlimit () možete dobiti ograničenje resursa navedeno u argumentu kao hrpu (meka granica, tvrda granica). Ovdje navodimo resource.RLIMIT_STACK kao resurs, koji predstavlja najveću veličinu stoga poziva trenutnog procesa.

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

U primjeru je meka granica 8388608 (8388608 B = 8192 KB = 8 MB), a tvrda granica -1 (neograničeno).

Ograničenje resursa možete promijeniti pomoću resource.setrlimit (). Ovdje je i meka granica postavljena na -1 (bez ograničenja). Također možete koristiti stalni resurs.RLIM_INFINIT za predstavljanje neograničenog ograničenja.

Sada se može izvesti duboka rekurzija, koja se nije mogla izvesti zbog greške segmentacije prije promjene veličine snopa.

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

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

recu_test(10 ** 5)
# Finish

Ovdje je meka granica postavljena na -1 (bez ograničenja) za jednostavan eksperiment, no u stvarnosti bi bilo sigurnije ograničiti je na odgovarajuću vrijednost.

Osim toga, kada sam pokušao postaviti neograničeno meko ograničenje i na svom macu, dogodila se sljedeća pogreška.ValueError: not allowed to raise maximum limit
Pokretanje skripte sa sudom nije pomoglo. Sustav ga može ograničiti.

Postupak s učinkovitim UID -om superkorisnika može zahtijevati bilo koje razumno ograničenje, uključujući i ograničenje.
Međutim, zahtjev koji premašuje ograničenje koje sustav nameće i dalje će rezultirati ValueError -om.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows nema modul resursa, a mac nije mogao promijeniti maksimalnu veličinu stoga zbog ograničenja sustava. Ako možemo na neki način povećati veličinu steka, trebali bismo moći riješiti grešku segmentacije, ali to nismo uspjeli potvrditi.