2010-04-27 19 views
8

He escrito un analizador de Python puro recursivo práctico para un formato de archivo (ARFF) que usamos en una conferencia. Ahora, ejecutar mi presentación de ejercicios es terriblemente lento. Resulta que, con mucho, se gasta más tiempo en mi analizador sintáctico. Está consumiendo mucho tiempo de CPU, el HD no es el cuello de botella.escribiendo un analizador rápido en python

Me pregunto qué formas efectivas hay para escribir un analizador en python? Prefiero no reescribirlo en C. Intenté usar jython, ¡pero eso disminuyó mucho el rendimiento! Los archivos que analizo son parcialmente enormes (> 150 MB) con líneas muy largas.

Mi analizador actual solo necesita una mirada anticipada de un caracter. Publicaría la fuente aquí, pero no sé si es una buena idea. Después de todo el plazo de presentación aún no ha terminado. Pero luego, el enfoque en este ejercicio no es el analizador sintáctico. Puedes elegir el idioma que quieras usar y ya hay un analizador para Java.

Nota: Tengo un sistema x86_64 así que psyco (y parece también PyPy) no es una opción.

Actualización: Ahora he subido mi analizador/escritor al bitbucket.

+4

¿Ha perfilado su analizador? Lo más probable es que sea solo un cuello de botella que lo contenga todo. –

+0

Sin un ejemplo de código, es imposible dar un consejo decente. Podría estar utilizando una técnica de sonido con un defecto importante, o podría ser necesario volver a trabajar todo su enfoque, no tenemos forma de saberlo. – mikerobi

+0

¿Has probado usar psyco con él? –

Respuesta

8

Puede usar ANTLR o pyparsing, pueden acelerar su proceso de análisis sintáctico.

Y si desea mantener su código actual, es posible que desee consultar Cython/PyPy, que aumenta su rendimiento (a veces hasta 4x).

+1

No es probable que pyparsing acelere las cosas, pero podría arrojar algunas ideas sobre dónde están los cuellos de botella. Además, creo que ya se ha escrito un analizador sintáctico de ARFF, y está en el éter en alguna parte. – PaulMcG

+0

Eso es cierto, y no sé cómo se adapta pyparsing con PyPy o Cython. – wvd

+0

El analizador de pirámide de ARFF vinculado desde el sitio de weka es extremadamente incompleto (si ese es el que está hablando). También he probado cython, pero debido a que utilizo mucho el rendimiento tuve que usar una versión de hg y todo lo que hice fue producir código que segfaults. – panzi

7

El consejo más general que daría sin más información sería leer todo el archivo, o al menos una parte sustancial de él, en la memoria a la vez. No desea leerlo un personaje a la vez y buscar aquí y allá; Independientemente del almacenamiento en búfer que se está llevando a cabo bajo el capó, probablemente sea una buena idea tener todo en la memoria para que pueda operarlo como lo desee.

He escrito analizadores en Python y no hay un requisito particular para que sean particularmente más lentos que un analizador escrito en cualquier otro idioma. Tal como sucede con este tipo de cosas, es más probable que esté haciendo un trabajo que no necesita hacer. De esa clase de elemento, crear, destruir y recrear el mismo objeto es más costoso que simplemente almacenarlo en alguna parte. Volver a calcular un valor una y otra vez es más costoso que solo almacenarlo en alguna parte. Etc., etc.

En Python específicamente, una trampa en la que las personas caen está haciendo una gran cantidad innecesaria de manipulación de cadenas. No agregue cadenas a un carácter a la vez; Cuando estés construyendo tus tokens haz tu trabajo en la secuencia "maestra" y quítate el token de una sola vez. (En otras palabras, indexe en la cadena "maestra", descubra los puntos de inicio y fin, y luego tóquelo con token = master[start:end]). Hacer la concatenación de cadenas de un carácter a la vez es una ruta corta hacia la miseria del rendimiento. Sospecho que incluso si quiere/necesita alguna razón para hacer for c in master: newstr += c, podría tener mejor suerte rellenando las "c" en una lista y luego newstr = ''.join(newstr_charlist).

+0

Uso mucho este tipo de cosas, ¿es esta la manera más rápida? Sin embargo, este código particular no es desencadenado por casos de uso. http://pastebin.com/yAmEcKB8 – panzi

+0

Ah, y leí fragmentos de 4096 bytes del archivo (los métodos readc() y peek() operan en estos trozos). No creo que sea una buena idea leer el archivo de agujeros porque los archivos tienen más de 150 MB de tamaño. – panzi

+2

Las computadoras modernas tienen 512M o más de memoria. Leer 150MB no es nada. :) –