Python recursion ကန့်သတ်ချက်ကို စစ်ဆေးပြီး ပြောင်းလဲပါ (ဥပမာ sys.setrecursionlimit)

စီးပွားရေးလုပ်ငန်း

Python တွင်၊ ထပ်ခါတလဲလဲအကြိမ်အရေအတွက် (အများဆုံးပြန်ယူသည့်အရေအတွက်) ၏အထက်ကန့်သတ်ချက်ရှိသည်။ ခေါ်ဆိုမှုအများအပြားဖြင့် recursive function ကိုလုပ်ဆောင်ရန်၊ ကန့်သတ်ချက်ကို ပြောင်းလဲရန်လိုအပ်သည်။ စံဒစ်ဂျစ်တိုက်၏ sys မော်ဂျူးတွင် လုပ်ဆောင်ချက်များကို အသုံးပြုပါ။

ထပ်ခါတလဲလဲ အရေအတွက်ကိုလည်း stack အရွယ်အစားအားဖြင့် ကန့်သတ်ထားသည်။ အချို့သောပတ်ဝန်းကျင်များတွင်၊ စံပြစာကြည့်တိုက်၏ အရင်းအမြစ် module သည် အများဆုံး stack အရွယ်အစားကိုပြောင်းလဲရန် (၎င်းသည် Ubuntu တွင်အလုပ်လုပ်သော်လည်း Windows သို့မဟုတ် mac တွင်မဟုတ်)။

အောက်ပါအချက်အလက်များကို ဤနေရာတွင် ဖော်ပြပေးထားပါသည်။

  • လက်ရှိပြန်ယူသည့်အရေအတွက်၏ အထက်ကန့်သတ်ချက်ကို ရယူပါ-sys.getrecursionlimit()
  • ထပ်ခါတလဲလဲ အရေအတွက်၏ အထက်ကန့်သတ်ချက်ကို ပြောင်းပါ-sys.setrecursionlimit()
  • stack ၏ အများဆုံးအရွယ်အစားကို ပြောင်းပါ-resource.setrlimit()

နမူနာကုဒ်သည် Ubuntu တွင် လုပ်ဆောင်နေသည်။

လက်ရှိပြန်ယူခြင်းကန့်သတ်ချက်ကို ရယူပါ- sys.getrecursionlimit()

လက်ရှိပြန်ယူခြင်းကန့်သတ်ချက်ကို sys.getrecursionlimit() ဖြင့် ရယူနိုင်ပါသည်။

import sys
import resource

print(sys.getrecursionlimit())
# 1000

ဥပမာတွင်၊ အများဆုံးပြန်ယူသည့်အရေအတွက်မှာ 1000 ဖြစ်ပြီး၊ ၎င်းသည် သင့်ပတ်ဝန်းကျင်ပေါ်မူတည်၍ ကွဲပြားနိုင်သည်။ ဤနေရာတွင် ကျွန်ုပ်တို့ တင်သွင်းနေသော အရင်းအမြစ်ကို နောက်ပိုင်းတွင် အသုံးပြုမည်ဖြစ်သော်လည်း Windows တွင် မဟုတ်ပါ။

ဥပမာအနေဖြင့်၊ ကျွန်ုပ်တို့သည် အောက်ပါရိုးရှင်းသော recursive function ကိုသုံးပါမည်။ အပြုသဘောဆောင်သော ကိန်းပြည့် 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

နောက်တွင်ရှင်းပြထားသည့်အတိုင်း ထပ်တလဲလဲပြုလုပ်သည့် အများဆုံးအရေအတွက်ကိုလည်း stack အရွယ်အစားဖြင့် ကန့်သတ်ထားသည်။

stack ၏ အများဆုံးအရွယ်အစားကို ပြောင်းပါ- resource.setrlimit()

sys.setrecursionlimit() တွင် ကြီးမားသောတန်ဖိုးကို သတ်မှတ်ထားလျှင်ပင် recursion အရေအတွက် များနေပါက ၎င်းကို လုပ်ဆောင်နိုင်မည်မဟုတ်ပေ။ ခွဲခြမ်းစိတ်ဖြာမှု အမှားသည် အောက်ပါအတိုင်း ဖြစ်ပေါ်ပါသည်။

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

# recu_test(10 ** 5)
# Segmentation fault

Python တွင်၊ စံဒစ်ဂျစ်တိုက်ရှိ အရင်းအမြစ် module သည် အများဆုံး stack အရွယ်အစားကို ပြောင်းလဲရန် အသုံးပြုနိုင်သည်။ သို့သော်၊ အရင်းအမြစ် module သည် Unix သီးသန့် module တစ်ခုဖြစ်ပြီး Windows တွင်အသုံးမပြုနိုင်ပါ။

resource.getrlimit() ဖြင့် သင်သည် အငြင်းအခုံတွင် သတ်မှတ်ထားသည့် အရင်းအမြစ်၏ ကန့်သတ်ချက်ကို (အပျော့စားကန့်သတ်ချက်၊ hard limit) တစ်ခုအဖြစ် သင်ရနိုင်သည်။ ဤနေရာတွင်၊ ကျွန်ုပ်တို့သည် အရင်းအမြစ်အဖြစ် သတ်မှတ်ပါသည်။ RLIMIT_STACK သည် လက်ရှိလုပ်ငန်းစဉ်၏ ခေါ်ဆိုမှုအစု၏ အများဆုံးအရွယ်အစားကို ကိုယ်စားပြုသည့် အရင်းအမြစ်အဖြစ် သတ်မှတ်ပါသည်။

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

ဥပမာတွင်၊ အပျော့စားကန့်သတ်ချက်မှာ 8388608 (8388608 B = 8192 KB = 8 MB) ဖြစ်ပြီး hard limit မှာ -1 (အကန့်အသတ်မရှိ) ဖြစ်သည်။

သင်သည် resource.setrlimit() ဖြင့် အရင်းအမြစ်၏ ကန့်သတ်ချက်ကို ပြောင်းလဲနိုင်သည်။ ဤတွင်၊ ပျော့ပျောင်းသောကန့်သတ်ချက်ကို -1 (ကန့်သတ်မရှိ) ဟုလည်းသတ်မှတ်ထားသည်။ အကန့်အသတ်မရှိ ကန့်သတ်ချက်ကို ကိုယ်စားပြုရန် စဉ်ဆက်မပြတ် ရင်းမြစ်ကိုလည်း သင်သုံးနိုင်သည်။

အစုခွဲအရွယ်အစားမပြောင်းလဲမီ ခွဲထွက်မှုအမှားကြောင့် မလုပ်ဆောင်နိုင်ခဲ့သည့် နက်နဲသောပြန်လှည့်ခြင်းကို ယခုလုပ်ဆောင်နိုင်ပါပြီ။

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 ဖြင့် ဇာတ်ညွှန်းကို run ရာတွင် မကူညီခဲ့ပါ။ စနစ်ဖြင့် ကန့်သတ်ထားနိုင်သည်။

စူပါအသုံးပြုသူ၏ ထိရောက်သော UID ပါသည့် လုပ်ငန်းစဉ်သည် အကန့်အသတ်မရှိအပါအဝင် ကျိုးကြောင်းဆီလျော်သော ကန့်သတ်ချက်ကို တောင်းဆိုနိုင်သည်။
သို့သော်၊ စနစ်က သတ်မှတ်သည့် ကန့်သတ်ချက်ထက်ကျော်လွန်သော တောင်းဆိုချက်သည် ValueError ဖြစ်နေဆဲဖြစ်သည်။
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation

Windows တွင်အရင်းအမြစ် module တစ်ခုမရှိသဖြင့် mac သည် system ကန့်သတ်ချက်များကြောင့်အများဆုံး stack အရွယ်အစားကိုမပြောင်းလဲနိုင်ခဲ့ပါ။ အကယ်၍ ကျွန်ုပ်တို့သည် stack အရွယ်အစားကိုတစ်နည်းနည်းဖြင့်တိုးမြှင့်နိုင်လျှင် segmentation fault ကိုဖြေရှင်းနိုင်သင့်သည်၊ ဒါပေမယ့်ဒါကိုအတည်ပြုလို့မရခဲ့ပါ။

Copied title and URL