Në Python, ekziston një kufi i sipërm për numrin e rekursioneve (numri maksimal i rekursioneve). Për të ekzekutuar një funksion rekurziv me një numër të madh thirrjesh, është e nevojshme të ndryshohet kufiri. Përdorni funksionet në modulin sys të bibliotekës standarde.
Numri i rekursioneve kufizohet gjithashtu nga madhësia e stivës. Në disa mjedise, moduli i burimeve të bibliotekës standarde mund të përdoret për të ndryshuar madhësinë maksimale të stivit (ai funksionoi në Ubuntu, por jo në Windows ose mac).
Informacioni i mëposhtëm jepet këtu.
- Merrni kufirin e sipërm të numrit aktual të rekursioneve:
sys.getrecursionlimit()
- Ndryshoni kufirin e sipërm të numrit të rekursioneve:
sys.setrecursionlimit()
- Ndryshoni madhësinë maksimale të pirgut:
resource.setrlimit()
Kodi i mostrës po funksionon në Ubuntu.
Merrni kufirin aktual të rekursionit: sys.getrecursionlimit()
Kufiri aktual i rekursionit mund të merret me sys.getrecursionlimit().
import sys
import resource
print(sys.getrecursionlimit())
# 1000
Në shembull, numri maksimal i rekursioneve është 1000, i cili mund të ndryshojë në varësi të mjedisit tuaj. Vini re se burimi që po importojmë këtu do të përdoret më vonë, por jo në Windows.
Si shembull, ne do të përdorim funksionin e thjeshtë rekurziv të mëposhtëm. Nëse një numër i plotë pozitiv n specifikohet si argument, numri i thirrjeve do të jetë n herë.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
Një gabim (RecursionError) do të ngrihet nëse përpiqeni të kryeni rekursion më shumë se kufiri i sipërm.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
Vini re se vlera e marrë nga sys.getrecursionlimit() nuk është rreptësisht numri maksimal i rekursioneve, por thellësia maksimale e stivës së interpretuesit Python, kështu që edhe nëse numri i rekursioneve është pak më i vogël se kjo vlerë, një gabim (RecursionError) do të të ngrihet.
再帰限界は、再帰の限界ではなく、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
Ndrysho kufirin e rekursionit: sys.setrecursionlimit()
Kufiri i sipërm i numrit të rekursioneve mund të ndryshohet nga sys.setrecursionlimit(). Kufiri i sipërm specifikohet si argument.
Lejon të kryhet rekursion më i thellë.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Nëse kufiri i sipërm i specifikuar është shumë i vogël ose shumë i madh, do të ndodhë një gabim. Ky kufizim (kufijtë e sipërm dhe të poshtëm të vetë kufirit) ndryshon në varësi të mjedisit.
Vlera maksimale e kufirit varet nga platforma. Nëse keni nevojë për rekursion të thellë, mund të specifikoni një vlerë më të madhe brenda intervalit të mbështetur nga platforma, por kini parasysh se kjo vlerë do të shkaktojë një përplasje nëse është shumë e madhe.
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
Numri maksimal i rekursioneve kufizohet gjithashtu nga madhësia e stivës, siç shpjegohet më poshtë.
Ndrysho madhësinë maksimale të pirgut: resource.setrlimit()
Edhe nëse një vlerë e madhe vendoset në sys.setrecursionlimit(), ajo mund të mos ekzekutohet nëse numri i rekursioneve është i madh. Një gabim segmentimi ndodh si më poshtë.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
Në Python, moduli i burimeve në bibliotekën standarde mund të përdoret për të ndryshuar madhësinë maksimale të stivit. Megjithatë, moduli i burimeve është një modul specifik i Unix-it dhe nuk mund të përdoret në Windows.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
Me resource.getrlimit(), ju mund të merrni kufirin e burimit të specifikuar në argument si një tufë prej (kufiri i butë, kufiri i vështirë). Këtu, ne specifikojmë burimin.RLIMIT_STACK si burim, i cili përfaqëson madhësinë maksimale të grupit të thirrjeve të procesit aktual.
- 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ë shembull, kufiri i butë është 8388608 (8388608 B = 8192 KB = 8 MB) dhe kufiri i fortë është -1 (i pakufizuar).
Ju mund të ndryshoni kufirin e burimit me resource.setrlimit(). Këtu, kufiri i butë është vendosur gjithashtu në -1 (pa kufi). Ju gjithashtu mund të përdorni burimin konstant.RLIM_INFINIT për të përfaqësuar kufirin e pakufizuar.
Rekursioni i thellë, i cili nuk mund të kryhej për shkak të gabimit të segmentimit përpara ndryshimit të madhësisë së stivës, tani mund të kryhet.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Këtu, kufiri i butë është vendosur në -1 (pa kufi) për një eksperiment të thjeshtë, por në realitet, do të ishte më e sigurt ta kufizosh atë në një vlerë të përshtatshme.
Përveç kësaj, kur u përpoqa të vendosja një kufi të pakufizuar të butë edhe në mac-in tim, ndodhi gabimi i mëposhtëm.ValueError: not allowed to raise maximum limit
Ekzekutimi i skenarit me sudo nuk ndihmoi. Mund të kufizohet nga sistemi.
Një proces me UID-in efektiv të një superpërdoruesi mund të kërkojë çdo kufi të arsyeshëm, duke përfshirë asnjë kufi.
Megjithatë, një kërkesë që tejkalon kufirin e vendosur nga sistemi do të rezultojë në një ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows nuk ka një modul burimesh dhe mac nuk mund të ndryshonte madhësinë maksimale të stivës për shkak të kufizimeve të sistemit. Nëse mund të rrisim madhësinë e stivës me disa mënyra, duhet të jemi në gjendje të zgjidhim gabimin e segmentimit, por nuk kemi qenë në gjendje ta konfirmojmë këtë.