Kiểm tra và thay đổi giới hạn đệ quy Python (ví dụ: sys.setrecursionlimit)

Kinh doanh

Trong Python, có giới hạn trên đối với số lần đệ quy (số lần đệ quy tối đa). Để thực hiện một hàm đệ quy với một số lượng lớn các cuộc gọi, cần phải thay đổi giới hạn. Sử dụng các chức năng trong mô-đun sys của thư viện chuẩn.

Số lần đệ quy cũng bị giới hạn bởi kích thước ngăn xếp. Trong một số môi trường, mô-đun tài nguyên của thư viện chuẩn có thể được sử dụng để thay đổi kích thước ngăn xếp tối đa (nó hoạt động trên Ubuntu, nhưng không hoạt động trên Windows hoặc mac).

Thông tin sau được cung cấp ở đây.

  • Nhận giới hạn trên của số lần đệ quy hiện tại:sys.getrecursionlimit()
  • Thay đổi giới hạn trên của số lần đệ quy:sys.setrecursionlimit()
  • Thay đổi kích thước tối đa của ngăn xếp:resource.setrlimit()

Mã mẫu đang chạy trên Ubuntu.

Nhận giới hạn đệ quy hiện tại: sys.getrecursionlimit ()

Giới hạn đệ quy hiện tại có thể đạt được bằng sys.getrecursionlimit ().

import sys
import resource

print(sys.getrecursionlimit())
# 1000

Trong ví dụ, số lần đệ quy tối đa là 1000, có thể thay đổi tùy thuộc vào môi trường của bạn. Lưu ý rằng tài nguyên chúng tôi đang nhập ở đây sẽ được sử dụng sau này, nhưng không được sử dụng trên Windows.

Ví dụ, chúng ta sẽ sử dụng hàm đệ quy đơn giản sau đây. Nếu một số nguyên dương n được chỉ định làm đối số, số lần gọi sẽ là n lần.

def recu_test(n):
    if n == 1:
        print('Finish')
        return
    recu_test(n - 1)

Lỗi (RecursionError) sẽ xuất hiện nếu bạn cố gắng thực hiện đệ quy nhiều hơn giới hạn trên.

recu_test(950)
# Finish

# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison

Lưu ý rằng giá trị thu được bởi sys.getrecursionlimit () không hoàn toàn là số lần đệ quy tối đa mà là độ sâu ngăn xếp tối đa của trình thông dịch Python, vì vậy ngay cả khi số lần đệ quy nhỏ hơn một chút giá trị này, lỗi (RecursionError) sẽ được nâng lên.

再 帰 限界 は 、 再 帰 の 限界 で は な く 、 タ ッ ク
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

Thay đổi giới hạn đệ quy: sys.setrecursionlimit ()

Giới hạn trên của số lần đệ quy có thể được thay đổi bằng sys.setrecursionlimit (). Giới hạn trên được chỉ định làm đối số.

Cho phép thực hiện đệ quy sâu hơn.

sys.setrecursionlimit(2000)

print(sys.getrecursionlimit())
# 2000

recu_test(1500)
# Finish

Nếu giới hạn trên được chỉ định quá nhỏ hoặc quá lớn, sẽ xảy ra lỗi. Ràng buộc này (giới hạn trên và giới hạn dưới của chính giới hạn) thay đổi tùy theo môi trường.

Giá trị tối đa của giới hạn phụ thuộc vào nền tảng. Nếu bạn cần đệ quy sâu, bạn có thể chỉ định một giá trị lớn hơn trong phạm vi được nền tảng hỗ trợ, nhưng lưu ý rằng giá trị này sẽ gây ra sự cố nếu nó quá lớn.
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

Số lần đệ quy tối đa cũng bị giới hạn bởi kích thước ngăn xếp, như được giải thích tiếp theo.

Thay đổi kích thước tối đa của ngăn xếp: resource.setrlimit ()

Ngay cả khi một giá trị lớn được đặt trong sys.setrecursionlimit (), nó có thể không được thực thi nếu số lượng đệ quy lớn. Một lỗi phân đoạn xảy ra như sau.

sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish

# recu_test(10 ** 5)
# Segmentation fault

Trong Python, mô-đun tài nguyên trong thư viện chuẩn có thể được sử dụng để thay đổi kích thước ngăn xếp tối đa. Tuy nhiên, mô-đun tài nguyên là một mô-đun dành riêng cho Unix và không thể được sử dụng trên Windows.

Với resource.getrlimit (), bạn có thể lấy giới hạn của tài nguyên được chỉ định trong đối số dưới dạng một bộ (giới hạn mềm, giới hạn cứng). Ở đây, chúng tôi chỉ định resource.RLIMIT_STACK làm tài nguyên, đại diện cho kích thước tối đa của ngăn xếp lệnh gọi của tiến trình hiện tại.

print(resource.getrlimit(resource.RLIMIT_STACK))
# (8388608, -1)

Trong ví dụ, giới hạn mềm là 8388608 (8388608 B = 8192 KB = 8 MB) và giới hạn cứng là -1 (không giới hạn).

Bạn có thể thay đổi giới hạn của tài nguyên bằng resource.setrlimit (). Ở đây, giới hạn mềm cũng được đặt thành -1 (không có giới hạn). Bạn cũng có thể sử dụng tài nguyên không đổi.RLIM_INFINIT để biểu thị giới hạn không giới hạn.

Đệ quy sâu, không thể thực hiện do lỗi phân đoạn trước khi thay đổi kích thước ngăn xếp, hiện có thể được thực hiện.

resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))

print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)

recu_test(10 ** 5)
# Finish

Ở đây, giới hạn mềm được đặt thành -1 (không có giới hạn) cho một thử nghiệm đơn giản, nhưng trên thực tế, sẽ an toàn hơn nếu giới hạn nó ở một giá trị thích hợp.

Ngoài ra, khi tôi cũng cố gắng đặt giới hạn mềm không giới hạn trên máy mac của mình, lỗi sau đã xảy ra.ValueError: not allowed to raise maximum limit
Chạy script với sudo không giúp được gì. Nó có thể bị hạn chế bởi hệ thống.

Một quy trình với UID hiệu quả của một siêu người dùng có thể yêu cầu bất kỳ giới hạn hợp lý nào, bao gồm cả không giới hạn.
Tuy nhiên, một yêu cầu vượt quá giới hạn do hệ thống áp đặt sẽ vẫn dẫn đến lỗi ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows không có mô-đun tài nguyên và mac không thể thay đổi kích thước ngăn xếp tối đa do giới hạn hệ thống. Nếu chúng ta có thể tăng kích thước ngăn xếp bằng một cách nào đó, chúng ta sẽ có thể giải quyết lỗi phân đoạn, nhưng chúng ta chưa thể xác nhận điều này.

Copied title and URL