ตรวจสอบและเปลี่ยนขีดจำกัดการเรียกซ้ำของ Python (เช่น sys.setrecursionlimit)

ธุรกิจ

ใน Python มีการจำกัดจำนวนการเรียกซ้ำสูงสุด (จำนวนการเรียกซ้ำสูงสุด) ในการเรียกใช้ฟังก์ชันแบบเรียกซ้ำที่มีการโทรจำนวนมาก จำเป็นต้องเปลี่ยนขีดจำกัด ใช้ฟังก์ชันในโมดูล sys ของไลบรารีมาตรฐาน

จำนวนการเรียกซ้ำยังถูกจำกัดด้วยขนาดสแต็ก ในบางสภาพแวดล้อม สามารถใช้โมดูลทรัพยากรของไลบรารีมาตรฐานเพื่อเปลี่ยนขนาดสแต็กสูงสุดได้ (ทำงานบน Ubuntu แต่ใช้งานไม่ได้บน Windows หรือ Mac)

ข้อมูลต่อไปนี้มีให้ที่นี่

  • รับขีดจำกัดสูงสุดของจำนวนการเรียกซ้ำปัจจุบัน:sys.getrecursionlimit()
  • เปลี่ยนขีดจำกัดสูงสุดของจำนวนการเรียกซ้ำ:sys.setrecursionlimit()
  • เปลี่ยนขนาดสูงสุดของสแต็ก:resource.setrlimit()

โค้ดตัวอย่างกำลังทำงานบน Ubuntu

รับขีดจำกัดการเรียกซ้ำปัจจุบัน: sys.getrecursionlimit()

สามารถรับขีดจำกัดการเรียกซ้ำปัจจุบันได้ด้วย sys.getrecursionlimit()

import sys
import resource

print(sys.getrecursionlimit())
# 1000

ในตัวอย่าง จำนวนการเรียกซ้ำสูงสุดคือ 1,000 ซึ่งอาจแตกต่างกันไปตามสภาพแวดล้อมของคุณ โปรดทราบว่าทรัพยากรที่เรากำลังนำเข้าที่นี่จะถูกนำมาใช้ในภายหลัง แต่ไม่ใช่ใน 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 – 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 ได้

ด้วย resource.getrlimit() คุณสามารถรับขีดจำกัดของทรัพยากรที่ระบุในอาร์กิวเมนต์เป็น tuple ของ (soft limit, hard limit) ที่นี่ เราระบุทรัพยากร RLIMIT_STACK เป็นทรัพยากร ซึ่งแสดงถึงขนาดสูงสุดของ call stack ของกระบวนการปัจจุบัน

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 ที่มีประสิทธิภาพของ superuser สามารถร้องขอขีดจำกัดที่สมเหตุสมผล รวมถึงไม่จำกัด
อย่างไรก็ตาม คำขอที่เกินขีดจำกัดที่กำหนดโดยระบบจะยังคงส่งผลให้เกิด ValueError
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows ไม่มีโมดูลทรัพยากร และ mac ไม่สามารถเปลี่ยนขนาดสแต็กสูงสุดได้เนื่องจากข้อจำกัดของระบบ หากเราสามารถเพิ่มขนาดสแต็กได้ด้วยวิธีใดวิธีหนึ่ง เราก็ควรจะสามารถแก้ไขข้อผิดพลาดในการแบ่งส่วนได้ แต่เราไม่สามารถยืนยันได้

Copied title and URL