2012-09-09 28 views
8

Para un programa C# AI utilizo una llamada recursiva para encontrar el mejor movimiento siguiente (usando una matriz 30x30 para almacenar el estado actual de la placa). Por cada movimiento que haga, quiero ver cuál de los movimientos posibles que puedo hacer desde el nuevo estado de la tabla será el mejor ... y así sucesivamente hasta que llegue a una posición de "fin del juego" (no hay más movimientos posibles en ese estado) o un temporizador detiene el proceso y no se realizan más llamadas recursivas (y se devuelve la "mejor" posición conocida). Esto solo para explicar por qué debo usar recursividad (no es recursividad de cola) y no puedo usar un solo estado de placa (global), pero debo buscar todos los estados de tabla posibles desde el estado actual.¿Hay alguna manera de verificar el tamaño de pila disponible antes de una llamada recursiva? (C#)

(A veces) Obtengo una System.StackOverflowException. ¿Hay alguna manera de verificar el espacio de pila disponible antes de la próxima llamada recursiva? Entonces podría simplemente devolver el estado actual como "la mejor posición encontrada hasta el momento" y no hacer la próxima llamada recursiva. Es decir. cuando la pila disponible se vuelve demasiado pequeña, también debería contar como caso base.

La otra opción, por supuesto, puede ser simplemente poner cada llamada recursiva en un bloque try..catch y manejar System.StackOverflowException usándolo como caso base?

+5

¿Rediseñar su código? Un stackoverflow es un signo de un código de error o mal (C#). Necesita una gran cantidad de llamadas recursivas para activar un stackoverflow. Use un lenguaje funcional que soporte llamadas de cola, como F #, si realmente desea hacerlo de esta manera. C# no está diseñado para eso. – Dykam

+0

"Si llama a un método recursivo o planea usar mucho espacio de pila, debe usar el método RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup". - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.probeforsufficientstack.aspx – DavidO

Respuesta

1

Si realmente desea seguir ese camino, puede utilizar el método EnsureSufficientExecutionstack.

Como otros señalaron, comenzando con .NET 2.0 que no puede captura un StackOverflowException, sin embargo, a partir de la documentación de MSDN que conocer el método anterior tiene el siguiente comportamiento:

asegura que el espacio de pila restante es lo suficientemente grande como para ejecutar la función de .NET Framework promedio .

Cuando la pila no es lo suficientemente grande según este método entonces se producirá una excepción InsufficientExecutionStackException que puede coger.

+0

¿Has probado eso? "Asegura que el espacio restante de la pila sea lo suficientemente grande como para ejecutar la función promedio de .NET Framework". En el caso de los OP, nunca puede haber suficiente espacio. ¿Cómo se conocería * este método *? –

+0

Cada nivel de recursión tendría que verificarse de nuevo, ¿no? – DavidO

+0

Esa parte es de la documentación de MSDN, debería haberle agregado un presupuesto, actualizaré la respuesta. Como señaló DavidO, el control debería realizarse en cada paso para que sea una solución válida. –

2

En realidad, el sistema ampliará dinámicamente el tamaño de la pila, si se quedara sin espacio en la pila existente. Entonces, incluso si pudiera probar el tamaño de la pila, en realidad no importaría.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx detalles

El sistema compromete páginas adicionales de la memoria de pila reservado a medida que se necesitan, hasta que la pila alcanza el tamaño reservado menos una página (que se utiliza como una página de protección para evitar desbordamiento de pila) o el sistema es tan poca memoria que la operación falla"

que ya es decir que, antes de que ocurra la recursividad, la pila es de un tamaño;. y si la recursividad provoca un desbordamiento de pila, la pila es una nuevo tamaño cuando eso sucedió.

Dado que no puede detectar el StackOverflowException, en lugar de la recursividad del terminal, puede utilizar la recursividad final. El siguiente enlace proporciona un buen detalle en la conversión de recusion terminal en recusion cola: http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/

+0

"(A veces) obtengo una excepción System.StackOverflowException". (Puede ser útil explicar eso.) – DavidO

+0

@DavidO, eso no quiere decir que a pesar de aumentar la pila mientras se está produciendo la recursión, se quedó sin memoria para expandir la pila. –

+0

Depende de la posición actual de la placa. Si la respuesta se encuentra lo suficientemente temprano (el caso base se encuentra temprano), normalmente no entiendo el problema. –

2

usted podría utilizar una cola + bucle (Queue<TNode> + while (queue.MoveNext())) en lugar de la recursión y limitar el tamaño de la cola.

O podría contar llamadas abiertas al método y limitar la recursión de esa manera. (Contar entradas y salidas y no ingresar recursividad si las entradas - existe> maxOpenCalls).

1

A partir de .NET 2 Usted no puede contraer StackOverflowException ...

La única manera de determinar qué parte de su pila ya se utiliza medios para utilizar código no seguro, que me encarecidamente no utilizar mejor ... una explícita basado en el montón Stack<T>.

Cuestiones relacionadas