Pythoni rekursiooni limiidi kontrollimine ja muutmine (nt sys.setrecursionlimit)

Äri

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.

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.

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.

Copied title and URL