Python хэл дээр рекурсын тоонд дээд хязгаар байдаг (хамгийн их рекурсын тоо). Олон тооны дуудлага бүхий рекурсив функцийг гүйцэтгэхийн тулд хязгаарыг өөрчлөх шаардлагатай. Стандарт номын сангийн sys модулийн функцуудыг ашиглана уу.
Рекурсын тоо нь стекийн хэмжээгээр хязгаарлагддаг. Зарим орчинд стандарт номын сангийн нөөцийн модулийг стекийн дээд хэмжээг өөрчлөхөд ашиглаж болно (энэ нь Ubuntu дээр ажилласан боловч Windows эсвэл mac дээр биш).
Дараах мэдээллийг эндээс хүргэж байна.
- Одоогийн рекурсын тооны дээд хязгаарыг авна уу:
sys.getrecursionlimit()
- Рекурсын тооны дээд хязгаарыг өөрчлөх:
sys.setrecursionlimit()
- Стекийн хамгийн их хэмжээг өөрчлөх:
resource.setrlimit()
Жишээ код нь Ubuntu дээр ажиллаж байна.
Одоогийн рекурсын хязгаарыг авна уу: sys.getrecursionlimit()
Одоогийн рекурсын хязгаарыг sys.getrecursionlimit() ашиглан авч болно.
import sys
import resource
print(sys.getrecursionlimit())
# 1000
Жишээн дээр рекурсын хамгийн их тоо нь 1000 бөгөөд таны орчноос хамаарч өөр өөр байж болно. Бидний энд оруулж байгаа эх сурвалжийг дараа нь ашиглах боловч Windows дээр ашиглахгүй гэдгийг анхаарна уу.
Жишээ болгон бид дараах энгийн рекурсив функцийг ашиглах болно. Хэрэв эерэг бүхэл тоо n-ийг аргумент болгон зааж өгсөн бол дуудлагын тоо n дахин их байх болно.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
Хэрэв та дээд хязгаараас илүү рекурс хийхийг оролдвол алдаа (RecursionError) гарч ирнэ.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
sys.getrecursionlimit()-ийн олж авсан утга нь рекурсын хамгийн их тоо биш, харин Python орчуулагчийн стекийн хамгийн их гүн байх тул рекурсын тоо энэ утгаас арай бага байсан ч алдаа (RecursionError) гарна гэдгийг анхаарна уу. өсгөх.
再帰限界は、再帰の限界ではなく、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
Рекурсын хязгаарыг өөрчлөх: sys.setrecursionlimit()
Рекурсын тооны дээд хязгаарыг sys.setrecursionlimit() ашиглан өөрчилж болно. Дээд хязгаарыг аргумент болгон зааж өгсөн.
Илүү гүнзгий рекурс хийх боломжийг олгодог.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Хэрэв заасан дээд хязгаар хэт бага эсвэл хэт том байвал алдаа гарна. Энэхүү хязгаарлалт (хязгаарлалтын дээд доод хязгаар) нь хүрээлэн буй орчноос хамаарч өөр өөр байдаг.
Хязгаарлалтын хамгийн их утга нь платформоос хамаарна. Хэрэв танд гүнзгий рекурс хийх шаардлагатай бол платформын дэмждэг мужид илүү том утгыг зааж өгч болно, гэхдээ энэ утга хэт том байвал сүйрэлд хүргэнэ гэдгийг анхаарна уу.
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
Дахин давтагдах хамгийн их тоо нь мөн дараагийн тайлбарласны дагуу стекийн хэмжээгээр хязгаарлагддаг.
Стекийн хамгийн их хэмжээг өөрчлөх: resource.setrlimit()
Хэдийгээр sys.setrecursionlimit()-д том утгыг тохируулсан ч рекурсын тоо их байвал энэ нь ажиллахгүй байж болно. Сегментийн алдаа дараах байдлаар үүсдэг.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
Python-д стандарт номын сан дахь нөөцийн модулийг стекийн дээд хэмжээг өөрчлөхөд ашиглаж болно. Гэсэн хэдий ч нөөцийн модуль нь Unix-д зориулагдсан модуль бөгөөд Windows дээр ашиглах боломжгүй.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
resource.getrlimit()-ийн тусламжтайгаар та аргументад заасан нөөцийн хязгаарыг (зөөлөн хязгаар, хатуу хязгаар)-ийн багц хэлбэрээр авах боломжтой. Энд бид resource.RLIMIT_STACK-г нөөц болгон зааж өгсөн бөгөөд энэ нь одоогийн процессын дуудлагын стекийн хамгийн их хэмжээг илэрхийлдэг.
- 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)
Жишээн дээр зөөлөн хязгаар нь 8388608 (8388608 B = 8192 KB = 8 MB), хатуу хязгаар нь -1 (хязгааргүй) байна.
Та нөөцийн хязгаарыг resource.setrlimit() ашиглан өөрчилж болно. Энд зөөлөн хязгаарыг мөн -1 (хязгааргүй) гэж тохируулсан. Та мөн хязгааргүй хязгаарыг илэрхийлэхийн тулд тогтмол нөөцийг ашиглаж болно.RLIM_INFINIT.
Стекийн хэмжээг өөрчлөхөөс өмнө сегментчилсэн алдаанаас болж хийгдэж чадаагүй гүн рекурсийг одоо хийж болно.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Энд энгийн туршилтын хувьд зөөлөн хязгаарыг -1 (хязгааргүй) гэж тогтоосон боловч бодит байдал дээр үүнийг зохих утгаар хязгаарлах нь илүү аюулгүй байх болно.
Нэмж дурдахад би өөрийн mac дээр хязгааргүй зөөлөн хязгаарлалт тавихыг оролдоход дараах алдаа гарсан.ValueError: not allowed to raise maximum limit
Скриптийг sudo ашиглан ажиллуулах нь тус болсонгүй. Энэ нь системээр хязгаарлагдаж магадгүй юм.
Супер хэрэглэгчийн үр дүнтэй UID-тэй процесс нь ямар ч боломжийн хязгаарыг шаардаж болно, үүнд хязгаарлалт байхгүй.
Гэсэн хэдий ч системээс тогтоосон хязгаараас хэтэрсэн хүсэлт нь ValueError-д хүргэсэн хэвээр байх болно.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows нь нөөцийн модульгүй бөгөөд Mac нь системийн хязгаарлалтын улмаас хамгийн их стекийн хэмжээг өөрчилж чадсангүй. Хэрэв бид стекийн хэмжээг ямар нэгэн байдлаар нэмэгдүүлэх боломжтой бол сегментчилсэн алдааг шийдвэрлэх боломжтой байсан ч үүнийг баталж чадаагүй байна.