În Python, există o limită superioară a numărului de recursiuni (numărul maxim de recursiuni). Pentru a executa o funcție recursivă cu un număr mare de apeluri, este necesar să se modifice limita. Utilizați funcțiile din modulul sys al bibliotecii standard.
Numărul de recursiuni este, de asemenea, limitat de dimensiunea stivei. În unele medii, modulul de resurse din biblioteca standard poate fi utilizat pentru a modifica dimensiunea maximă a stivei (a funcționat pe Ubuntu, dar nu și pe Windows sau mac).
Aici sunt furnizate următoarele informații.
- Obține limita superioară a numărului actual de recurențe:
sys.getrecursionlimit()
- Modificați limita superioară a numărului de recurențe:
sys.setrecursionlimit()
- Modificați dimensiunea maximă a stivei:
resource.setrlimit()
Codul de exemplu rulează pe Ubuntu.
Obțineți limita curentă de recursivitate: sys.getrecursionlimit()
Limita curentă a recursivității poate fi obținută cu sys.getrecursionlimit().
import sys
import resource
print(sys.getrecursionlimit())
# 1000
În acest exemplu, numărul maxim de recurențe este de 1000, care poate varia în funcție de mediul dumneavoastră. Rețineți că resursa pe care o importăm aici va fi utilizată mai târziu, dar nu în Windows.
Ca exemplu, vom folosi următoarea funcție recursivă simplă. Dacă se specifică un număr întreg pozitiv n ca argument, numărul de apeluri va fi de n ori.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
O eroare (RecursionError) va fi generată dacă încercați să efectuați o recursivitate mai mare decât limita superioară.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
Rețineți că valoarea obținută de sys.getrecursionlimit() nu este strict numărul maxim de recurențe, ci adâncimea maximă a stivei interpretorului Python, astfel încât, chiar dacă numărul de recurențe este puțin mai mic decât această valoare, se va afișa o eroare (RecursionError).
Limita de recursivitate nu este limita de recursivitate, ci adâncimea maximă a stivei interpretorului 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
Modificarea limitei de recursivitate: sys.setrecursionlimit()
Limita superioară a numărului de recurențe poate fi modificată prin sys.setrecursionlimit(). Limita superioară este specificată ca argument.
Permite efectuarea unei recursivități mai profunde.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Dacă limita superioară specificată este prea mică sau prea mare, se va produce o eroare. Această constrângere (limitele superioare și inferioare ale limitei propriu-zise) variază în funcție de mediu.
Valoarea maximă a limitei depinde de platformă. Dacă aveți nevoie de o recursivitate profundă, puteți specifica o valoare mai mare în intervalul acceptat de platformă, dar trebuie să știți că această valoare va provoca o eroare dacă este prea mare.
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
Numărul maxim de recursiuni este, de asemenea, limitat de dimensiunea stivei, după cum se explică în continuare.
Modificați dimensiunea maximă a stivei: resource.setrlimit()
Chiar dacă se stabilește o valoare mare în sys.setrecursionlimit(), este posibil să nu fie executată dacă numărul de recursiuni este mare. O eroare de segmentare se produce după cum urmează.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
În Python, modulul de resurse din biblioteca standard poate fi utilizat pentru a modifica dimensiunea maximă a stivei. Cu toate acestea, modulul de resurse este un modul specific Unix și nu poate fi utilizat pe Windows.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
Cu resource.getrlimit(), puteți obține limita resursei specificate în argument sub forma unui tuplu de (soft limit, hard limit). În acest caz, specificăm resursa resource.RLIMIT_STACK ca resursă, care reprezintă dimensiunea maximă a stivei de apeluri a procesului curent.
- resource.getrlimit() — Resource usage information — Python 3.10.0 Documentation
- resource.RLIMIT_STACK — Resource usage information — Python 3.10.0 Documentation
print(resource.getrlimit(resource.RLIMIT_STACK))
# (8388608, -1)
În acest exemplu, limita soft este 8388608 (8388608 B = 8192 KB = 8 MB), iar limita hard este -1 (nelimitat).
Puteți modifica limita resursei cu resource.setrlimit(). Aici, limita soft este, de asemenea, setată la -1 (fără limită). De asemenea, puteți utiliza constanta resource.RLIM_INFINIT pentru a reprezenta limita nelimitată.
Recursivitatea profundă, care nu a putut fi efectuată din cauza unei erori de segmentare înainte de modificarea dimensiunii stivei, poate fi efectuată acum.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Aici, limita soft este setată la -1 (nicio limită) pentru un experiment simplu, dar, în realitate, ar fi mai sigur să se limiteze la o valoare adecvată.
În plus, atunci când am încercat să setez o limită soft nelimitată și pe Mac-ul meu, a apărut următoarea eroare.ValueError: not allowed to raise maximum limit
Rularea scriptului cu sudo nu a ajutat. Este posibil să fie restricționat de sistem.
Un proces cu UID-ul efectiv al unui superutilizator poate solicita orice limită rezonabilă, inclusiv nicio limită.
Cu toate acestea, o cerere care depășește limita impusă de sistem va avea ca rezultat un ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows nu are un modul de resurse, iar mac nu a putut modifica dimensiunea maximă a stivei din cauza limitărilor de sistem. Dacă putem mări dimensiunea stivei prin anumite mijloace, ar trebui să putem rezolva problema defecțiunii de segmentare, dar nu am putut confirma acest lucru.