Pythonis on rekursioonide arvule ülemine piir (rekursioonide maksimaalne arv). Suure hulga kõnedega rekursiivse funktsiooni täitmiseks on vaja seda piirmäära muuta. Kasutage standardraamatukogu sys-mooduli funktsioone.
Rekursioonide arvu piirab ka virna suurus. Mõnes keskkonnas saab standardraamatukogu ressursimoodulit kasutada maksimaalse virna suuruse muutmiseks (Ubuntus töötas see, kuid Windowsis või macil mitte).
Siin on esitatud järgmine teave.
- Saab praeguse rekursioonide arvu ülemise piiri:
sys.getrecursionlimit()
- Muutke rekursioonide arvu ülempiiri:
sys.setrecursionlimit()
- Muutke virna maksimaalset suurust:
resource.setrlimit()
Näidiskood töötab Ubuntul.
Saada praegune rekursioonilimiit: sys.getrecursionlimit()
Praeguse rekursioonilimiidi saab teada sys.getrecursionlimit() abil.
import sys
import resource
print(sys.getrecursionlimit())
# 1000
Näites on rekursioonide maksimaalne arv 1000, mis võib sõltuvalt teie keskkonnast erineda. Pange tähele, et ressurssi, mida me siin impordime, kasutatakse hiljem, kuid mitte Windowsis.
Näitena kasutame järgmist lihtsat rekursiivset funktsiooni. Kui argumendiks on antud positiivne täisarv n, siis on kutsete arv n korda.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
Viga (RecursionError) ilmneb, kui proovite teha rekursiooni rohkem kui ülemine piir.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
Pange tähele, et sys.getrecursionlimit() abil saadud väärtus ei ole otseselt rekursioonide maksimaalne arv, vaid Pythoni interpretaatori maksimaalne virna sügavus, nii et isegi kui rekursioonide arv on veidi väiksem kui see väärtus, tekib viga (RecursionError).
Rekursiooni piir ei ole rekursiooni piir, vaid pythoni interpretaatori virna maksimaalne sügavus.
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
Muuda rekursiooni limiiti: sys.setrecursionlimit()
Rekursioonide arvu ülemist piiri saab muuta sys.setrecursionlimit() abil. Ülempiir määratakse argumendina.
Võimaldab sügavamat rekursiooni.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Kui määratud ülemine piir on liiga väike või liiga suur, tekib viga. See piirang (piirmäära ülemine ja alumine piir ise) varieerub sõltuvalt keskkonnast.
Piirnormi maksimaalne väärtus sõltub platvormist. Kui teil on vaja sügavat rekursiooni, võite määrata suurema väärtuse platvormi poolt toetatud vahemikus, kuid arvestage, et liiga suur väärtus põhjustab krahhi.
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
Rekursioonide maksimaalne arv on samuti piiratud virna suurusega, nagu on selgitatud allpool.
Muutke virna maksimaalset suurust: resource.setrlimit()
Isegi kui sys.setrecursionlimit() funktsioonis on määratud suur väärtus, ei pruugi seda täita, kui rekursioonide arv on suur. Segmentatsiooniviga tekib järgmiselt.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
Pythonis saab kasutada standardraamatukogu ressursimoodulit, et muuta maksimaalset virna suurust. Ressursimoodul on aga Unixi spetsiifiline moodul ja seda ei saa kasutada Windowsis.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
Resource.getrlimit() abil saate saada argumendis määratud ressursi limiidi (soft limit, hard limit) tuplina. Siin anname ressursina resource.RLIMIT_STACK, mis kujutab endast praeguse protsessi kõnehulga maksimaalset suurust.
- 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äites on pehme piir 8388608 (8388608 B = 8192 KB = 8 MB) ja raske piir -1 (piiramatu).
Ressursi piirangut saab muuta funktsiooniga resource.setrlimit(). Siin on ka pehme limiit seatud väärtuseks -1 (piirangut ei ole). Piiramatu limiidi tähistamiseks võib kasutada ka konstanti resource.RLIM_INFINIT.
Sügavat rekursiooni, mida enne virna suuruse muutmist segmenteerimisvea tõttu ei saanud teostada, saab nüüd teostada.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Siin on pehmeks piiriks seatud -1 (piirangut ei ole) lihtsa eksperimendi jaoks, kuid tegelikkuses oleks turvalisem piirata seda sobiva väärtusega.
Lisaks, kui ma proovisin ka oma mac'ile piiramatut pehmet piirangut seada, ilmnes järgmine viga.ValueError: not allowed to raise maximum limit
Skripti käivitamine sudoga ei aidanud. See võib olla süsteemi poolt piiratud.
Protsess, mille tegelik UID on suurkasutaja, võib taotleda mis tahes mõistlikku piirangut, sealhulgas piirangut ei ole.
Süsteemi poolt kehtestatud piirmäära ületav päring annab siiski ValueError'i.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windowsil ei ole ressursimoodulit ja mac ei saanud süsteemipiirangute tõttu maksimaalset virna suurust muuta. Kui me suudame virna suurust mingi vahendiga suurendada, peaksime suutma segmenteerimisvea lahendada, kuid me ei ole suutnud seda kinnitada.