Periksa dan ubah had rekursi Python (mis. Sys.setrecursionlimit)

Perniagaan

Di Python, terdapat had atas bilangan rekursi (jumlah maksimum rekursi). Untuk menjalankan fungsi rekursif dengan sebilangan besar panggilan, perlu mengubah hadnya. Gunakan fungsi dalam modul sys perpustakaan standard.

Bilangan rekursi juga dibatasi oleh ukuran timbunan. Di beberapa persekitaran, modul sumber perpustakaan standard dapat digunakan untuk mengubah ukuran tumpukan maksimum (ia berfungsi di Ubuntu, tetapi tidak pada Windows atau mac).

Maklumat berikut diberikan di sini.

  • Dapatkan had atas jumlah pengulangan semasa:sys.getrecursionlimit()
  • Tukar had atas bilangan pengulangan:sys.setrecursionlimit()
  • Tukar ukuran timbunan maksimum:resource.setrlimit()

Contoh kod sedang dijalankan di Ubuntu.

Dapatkan had rekursi semasa: sys.getrecursionlimit ()

Had rekursi semasa boleh didapati dengan sys.getrecursionlimit ().

import sys
import resource

print(sys.getrecursionlimit())
# 1000

Contohnya, jumlah rekursi maksimum adalah 1000, yang mungkin berbeza bergantung pada persekitaran anda. Perhatikan bahawa sumber yang kita impor di sini akan digunakan kemudian, tetapi tidak pada Windows.

Sebagai contoh, kami akan menggunakan fungsi rekursif sederhana berikut. Sekiranya bilangan bulat positif n dinyatakan sebagai argumen, jumlah panggilan akan menjadi n kali.

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

Kesalahan (RecursionError) akan dibangkitkan jika anda cuba melakukan rekursi melebihi had atas.

recu_test(950)
# Finish

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

Perhatikan bahawa nilai yang diperoleh oleh sys.getrecursionlimit () bukanlah bilangan berulang maksimum, tetapi kedalaman timbunan maksimum pentafsir Python, jadi walaupun jumlah pengulangan sedikit lebih sedikit daripada nilai ini, ralat (RecursionError) akan berlaku dibangkitkan.

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

Tukar had rekursi: sys.setrecursionlimit ()

Had atas bilangan pengulangan boleh diubah oleh sys.setrecursionlimit (). Had atas ditentukan sebagai argumen.

Membolehkan pengulangan yang lebih mendalam dilakukan.

sys.setrecursionlimit(2000)

print(sys.getrecursionlimit())
# 2000

recu_test(1500)
# Finish

Sekiranya had atas yang ditentukan terlalu kecil atau terlalu besar, kesalahan akan berlaku. Kekangan ini (had atas dan bawah had itu sendiri) berbeza bergantung pada persekitaran.

Nilai had maksimum bergantung pada platform. Sekiranya anda memerlukan pengulangan yang mendalam, anda dapat menentukan nilai yang lebih besar dalam rentang yang disokong oleh platform, tetapi ketahuilah bahawa nilai ini akan menyebabkan kerosakan jika terlalu besar.
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

Jumlah rekursi maksimum juga dibatasi oleh ukuran timbunan, seperti yang dijelaskan selanjutnya.

Tukar ukuran timbunan maksimum: resource.setrlimit ()

Walaupun nilai besar ditetapkan dalam sys.setrecursionlimit (), nilai tersebut tidak dapat dilaksanakan jika jumlah pengulangannya besar. Kesalahan segmentasi berlaku seperti berikut.

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

# recu_test(10 ** 5)
# Segmentation fault

Di Python, modul sumber di perpustakaan standard dapat digunakan untuk mengubah ukuran timbunan maksimum. Walau bagaimanapun, modul sumber adalah modul khusus Unix dan tidak dapat digunakan pada Windows.

Dengan resource.getrlimit (), anda boleh mendapatkan had sumber yang ditentukan dalam argumen sebagai tuple (had lembut, had keras). Di sini, kami menentukan sumber.RLIMIT_STACK sebagai sumber, yang mewakili ukuran maksimum timbunan panggilan dari proses semasa.

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

Dalam contoh, had lembut ialah 8388608 (8388608 B = 8192 KB = 8 MB) dan had keras adalah -1 (tidak terhad).

Anda boleh mengubah had sumber dengan resource.setrlimit (). Di sini, had lembut juga ditetapkan ke -1 (tanpa had). Anda juga boleh menggunakan sumber tetap.RLIM_INFINIT untuk mewakili had yang tidak terhad.

Rekursi mendalam, yang tidak dapat dilakukan karena kesalahan segmentasi sebelum perubahan ukuran timbunan, kini dapat dilakukan.

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

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

recu_test(10 ** 5)
# Finish

Di sini, had lembut ditetapkan ke -1 (tanpa had) untuk eksperimen sederhana, tetapi pada hakikatnya, lebih selamat untuk membatasinya ke nilai yang sesuai.

Di samping itu, semasa saya cuba menetapkan had lembut yang tidak terhad pada mac saya juga, ralat berikut berlaku.ValueError: not allowed to raise maximum limit
Menjalankan skrip dengan sudo tidak membantu. Mungkin dibatasi oleh sistem.

Proses dengan UID berkesan pengguna boleh meminta had yang munasabah, termasuk had.
Namun, permintaan yang melebihi had yang dikenakan oleh sistem akan tetap menghasilkan ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows tidak mempunyai modul sumber, dan mac tidak dapat mengubah ukuran tumpukan maksimum kerana keterbatasan sistem. Sekiranya kita dapat meningkatkan ukuran timbunan dengan beberapa cara, kita seharusnya dapat menyelesaikan kesalahan segmentasi, tetapi kita belum dapat mengesahkannya.