- Как расшифровать Exit code?
- Python-сообщество
- #1 Сен. 20, 2017 22:18:56
- Рекурсия и мой компьютер
- #2 Сен. 21, 2017 00:16:32
- Рекурсия и мой компьютер
- #3 Сен. 21, 2017 13:41:00
- Рекурсия и мой компьютер
- #4 Сен. 21, 2017 14:02:37
- Рекурсия и мой компьютер
- #5 Сен. 21, 2017 15:07:03
- Рекурсия и мой компьютер
- #6 Сен. 21, 2017 15:11:40
- Рекурсия и мой компьютер
- Исправление Python 0xC00000FD без потока
- 2 ответа
Как расшифровать Exit code?
Ну и рекурсию надо «размотать». А то она слишком «замотана». Замоталась.
Вы поставили ограничение глубины стека таким большим, что память заканчивается задолго до достижения этого лимита, поэтому ваш процесс интерпретатора падает не показывая валидную ошибку.
Не стоит делать такой неадекватный лимит стека, тогда ваш интерпретатор упадёт с другой ошибкой — превышен лимит рекурсивных вызовов.
А уж эту проблему решать надо оптимизацией алгоритма. Ваш слишком жаден до стека.
Изменил программу для нахождения простых чисел (для начала) вроде не зацикливается, но все равно выдает ошибку
RecursionError: maximum recursion depth exceeded in comparison
# Каков самый большой делитель числа 600851475143, являющийся простым числом? import sys #sys.setrecursionlimit(2**30) d = 1 n = 1241452 def main(): ar = [] simp = [] # def delit(d): # global a # global n # if n % d == 0: # ar.append(d) # n = n/d # if n == 1: # print(ar) # else: # delit(2) # else: # a = simp_ind(d) def simp_ind(d): for i in range(10): p = 2 d +=1 while d % p != 0: p += 1 if p == d: simp.append(d) else: simp_ind(d) simp_ind(d) print(simp) if __name__ == '__main__': main()
Marty1337, потому что плохо реализовали.
Любую рекурсию можно заменить итеративным алгоритмом со стеком в качестве которого можно использовать тот же список.
В таком случае в стеке у вас будет лежать не весь контекст функуии, а только одно значение. Это более экономно.
Попробуйте описать алгоритм на человеческом и математическом языке, а потом уже беритесь писать программу. Складывается ощущение, что вы её пишете методом проб и ошибок.
Прочитайте что такое «чистые функции» и что такое «побочный эффект» в этом контексте. Старайтесь писать чистые функции.
Рекурсия в задачах вроде этой очень неэкономична. тем более, если вы ее не пытаетесь оптимизировать и экономично использовать стек.
Нужно пользоваться встроенными питоновскими структурами данных вроде словарей, которые позволяют получать значение по ключу за ~O(1). На этом можно построить много оптимизаций
Marty1337, любая рекурсия должна иметь критерий остановки. Иначе это не рекурсия, а ошибка.
Зачем проверять делимость на каждое число? Все четные можно исключить кроме 2, все кратные 3 кроме 3 и т.д. Вы же решаете задачу очень неэффективно.
Python-сообщество
- Начало
- » Python для новичков
- » Рекурсия и мой компьютер
#1 Сен. 20, 2017 22:18:56
Рекурсия и мой компьютер
import random import sys print(sys.getrecursionlimit()) sys.setrecursionlimit(40000) print(sys.getrecursionlimit()) g = [] for i in range(200): b = random.randint(0, 1241) g.append(b) def sorter(): global g for i, k in enumerate(g): try: if g[i] > g[i + 1]: g[i], g[i + 1] = g[i + 1], g[i] return sorter() except IndexError: break sorter() print(g)
Пытался создать что то похожее на метод sort() и столкнулся с интересным поведением змеи. При запуске этого кода на моём пк интерпретатор выдаёт вот такую ошибку:
Process finished with exit code -1073741571 (0xC00000FD)
Причём пишет только это, никакой трэйсбэк не вылетает и красные слова тоже. Решил запустить через онлайн компилятор — всё заработало прекрасно и ошибки никакой не было.
Лучший учитель — это ты сам.
Отредактировано Djo0513 (Сен. 20, 2017 22:19:57)
#2 Сен. 21, 2017 00:16:32
JOHN_16 От: Россия, Петропавловск-Камчатск Зарегистрирован: 2010-03-22 Сообщения: 3292 Репутация: 221 Профиль Отправить e-mail
Рекурсия и мой компьютер
Вы гуглить видимо совсем не пробовали. Подумали что нашли что то сверх неординарное и надо быстрее показать это сообществу. Однако первая же ссылка в гугле расставляет все на места — StackOverflow.com
_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com
Отредактировано JOHN_16 (Сен. 21, 2017 00:17:44)
#3 Сен. 21, 2017 13:41:00
Рекурсия и мой компьютер
JOHN_16
Не все родились с пониманием английского. Я смотрел на stack overflow, но кроме того что надо подключать потоки ничего не понял, поэтому я задал вопрос сюда, чтоб меня разъяснили.
Это точно раздел для новичков?
Лучший учитель — это ты сам.
#4 Сен. 21, 2017 14:02:37
Рекурсия и мой компьютер
Отредактировано WoMax (Сен. 21, 2017 14:03:20)
#5 Сен. 21, 2017 15:07:03
Rodegast От: Пятигорск Зарегистрирован: 2007-12-28 Сообщения: 2611 Репутация: 179 Профиль Отправить e-mail
Рекурсия и мой компьютер
> Не все родились с пониманием английского.
С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.
#6 Сен. 21, 2017 15:11:40
Рекурсия и мой компьютер
Djo0513 Если вкратце то 0xC00000FD это переполнение стека (stack owerflow)
тут https://msdn.microsoft.com/en-us/library/cc704588.aspx можно посмотреть все коды ошибок корпорации зла MS.
по ссылке на StackOverflow, котороую вам дал JOHN_16, советуют увеличить размер стека.
По той же ссылке рекомендуют использовать threading где этот размер можно указать ручками threading.stack_size() при создании новой нити.
но можете использовать CreateThread из winAPI https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx или любое другое решение которое посчитаете приемлимым.
Надо бателька стараться, если хотите заниматься програмированием, без этого никак.
ЗЫ да у меня тоже все работает , не вызывая перепонения стека.
Отредактировано PEHDOM (Сен. 21, 2017 15:12:57)
Исправление Python 0xC00000FD без потока
У меня есть программа, которая должна делать очень глубокую рекурсию. Я увеличил предел рекурсии до 10**6, используя sys.setrecursionlimit(10**6) . Однако процесс завершился с этим кодом ошибки:
Process finished with exit code -1073741571 (0xC00000FD)
Прочитав этот вопрос, оказывается, что рекурсия limit не изменяет размер стека, поэтому произошло переполнение стека. Решением вопроса было использование threading.stack_size() , однако я новичок в Python и поэтому не понимаю, как использовать потоки.
Итак, как исправить 0xC00000FD в основном потоке?
Я проверял несколько раз — у меня нет бесконечного цикла, просто моя рекурсия очень глубокая.
Редактировать 30.10.2021: многие люди здесь рекомендуют переписать код, чтобы использовать итеративный (цикл), а не рекурсивный, и я так и сделал. Теперь мой код больше работает без ошибки переполнения стека. Но если кто-нибудь знает, как увеличить размер стека основного потока, не стесняйтесь отвечать здесь, мне все еще любопытно, есть ли способ увеличить размер стека основного потока python, потому что можно увеличить размер стека основного потока на другом языке, который я изучил например джава.
Вероятно, вам просто не следует использовать рекурсию, то есть явный стек ( stack = [] , stack.pop() , stack.append(…) ) и цикл.
@Ry- мой код объектно-ориентирован, каждый объект хранит ссылку на другой объект, который также сохраняет ссылку на другой объект и так далее до первого объекта, чтобы не использовать рекурсию, мне пришлось бы переписать весь код 🙁
Размер стека для основного потока в Windows задается компоновщиком, поэтому это будет размер стека python.exe. dumpbin говорит 2000000 (0x1E8480) для моей локальной копии. Если вы выполняете рекурсию достаточно глубоко, чтобы привести к сбою python.exe, вам нужно переосмыслить свой подход.
Как насчет того, чтобы написать минимально воспроизводимый пример и посмотреть, как его можно переписать. Как указано в комментарии, каждую рекурсивную функцию можно переписать со стеком и циклом. Кроме того, изображение — очень плохой носитель для передачи текстовых данных. Вместо этого скопируйте и вставьте, это облегчит чтение и исследование, а также уменьшит потребление памяти и пропускной способности.
2 ответа
Я был немного удивлен, обнаружив, что настройка размера стека потоков работает (на моей машине с Linux и, я думаю, с Windows тоже сработает). Я написал тест, который повторяется с потоком и без него, и результаты следующие:
$ python3 recurse.py Testing unthreaded try 10**4 10000 try 10**5 Segmentation fault (core dumped) $ python3 recurse.py threaded Testing threaded try 10**4 10000 try 10**5 100000 try 10**6 Exception in thread Thread-3: . RecursionError: maximum recursion depth exceeded in comparison
Код создает класс, наследуемый от threading.Thread . Инициализатор запускается и присоединяется к своему собственному потоку, поэтому просто создайте его экземпляр, и вы отправитесь в гонки. Управление размером стека является глобальным для модуля потоковой обработки — вызывает недоумение тот факт, что модуль потоковой передачи сам по себе не является потокобезопасным, поэтому он устанавливается непосредственно перед запуском кода и сбрасывается при запуске.
import threading import sys # usage: recurse.py [threaded] sys.setrecursionlimit(10**6) class MyRecursionThread(threading.Thread): """Start the recursion function in a separate thread and wait til complete""" def __init__(self, depth): super().__init__() self.orig_stack_size = threading.stack_size() threading.stack_size(100000*4096) # guessing here self.depth = depth self.start() self.join() def run(self): # thread is started so return default. Why isn't this # thread safe in the threading module. threading.stack_size(self.orig_stack_size) self.result = the_recursive_function(0, self.depth) def the_recursive_function(cur, depth): if cur < depth: return the_recursive_function(cur+1, depth) else: return cur # probe depth try: threaded = sys.argv[1] == "threaded" except IndexError: threaded = False print("Testing", "threaded" if threaded else "unthreaded") for i in range(4, 8): print(f"try 10**") if threaded: result = MyRecursionThread(10**i).result else: result = the_recursive_function(0, 10**i) print(result)
«Управление размером стека является глобальным для модуля потоковой передачи — вызывает недоумение тот факт, что модуль потоковой передачи сам по себе не является потокобезопасным» — я ожидал, что это будет ограничение на уровне ОС, но глядя на фактические механизмы уровня ОС, как Windows, так и POSIX потоки имеют аргумент для установки размера стека для определенного потока при создании этого потока.
- Исторически сложилось так, что размеры стека потоков по умолчанию были довольно малы, но по мере увеличения виртуального адресного пространства вы могли выбрать число, которое покрывает почти все. Тем не менее, у скупости есть свои преимущества — меньше выделений страниц. Я не знаю, как это работает в наши дни, но как только страница была выделена для стека, она оставалась закрепленной в стеке, поэтому одно жадное использование стека влияло на доступность памяти до тех пор, пока оно не прекратится.
Если вам в конечном итоге придется преобразовать ваши рекурсивные функции в итерационные подходы, этот декоратор/класс может помочь облегчить боль (в зависимости от характера ваших рекурсий).
Декоратор преобразует рекурсивные вызовы в функции в итерационные вызовы с внутренним (неограниченным) стеком. Его основные ограничения заключаются в том, что он поддерживает только простые рекурсии, в которых вызов самого себя является частью оператора return, и требует изменения способа выражения этого оператора return. Кроме того, это добавит значительные накладные расходы на вызовы функций, что повлияет на производительность.
Схема использования следующая:
@iterative # decorator to modify the function def fn(. ) # existing declaration . # and implementation if baseCase return x # no change to the base case return fn(. ),lambda x: . # isolate alterations to the recursed # result in a lambda
@iterative def factorial(n): if n
from collections import deque class iterative: def __init__(self,func): self.func = func # decorated function self.stack = deque() # [(argCount, function to call)] self.nested = False # nested call flag self.recursed = False # call wants recursion self.results = [] # result stack def __call__(self,*args,**kwargs): # replaces original function if self.nested: self.recursed = True # defer recursive call to make return lambda: self.func(*args,**kwargs) else: self.nested = True self.stack.append((0,lambda: self.func(*args,**kwargs))) # top while self.stack: useArgs,fn = self.stack.pop() # unstack if useArgs: # lambda on results args = self.results[-useArgs:] self.results = self.results[:-useArgs] self.results.append(fn(*args)) else: self.recursed = False # recursive call result = fn() if self.recursed: # more recursion -> stack *calls,final = result self.stack.append((len(calls),final)) self.stack.extend([(0,r) for r in reversed(calls)]) else: self.results.append(result) # base cond. -> results self.nested = False return self.results.pop(-1) # final result (and reset)