2011-11-16 17 views
6

¿Cuál es el método más rápido para convertir una cadena de datos binarios a un valor numérico en Python?conversión rápida de datos binarios en Python

Estoy usando struct.unpack_from(), pero estoy alcanzando un límite de rendimiento.

Contexto: una secuencia entrante es una mezcla de datos binarios y ASCII. La conversión de datos ASCII se realiza en C aunque ctypes. Implementar el desempaquetado en C a través de ctypes produjo un rendimiento similar para desempaquetar. Mi suposición es que la llamada sobrecarga fue demasiado factor. Esperaba encontrar un método de coerción nativo tipo C (sin embargo antipático). Lo más probable es que todo este código deba moverse a C.

La transmisión está en orden de bytes de red (big-endian) y la máquina es little-endian. Un ejemplo sería la conversión:

import struct 
network_stream = struct.pack('>I', 0x12345678) 
(converted_int,) = struct.unpack_from('>I', network_stream, 0) 

estoy menos preocupado por el manejo del formato de flujo, que en el caso general de conversión binaria, y si hay incluso una alternativa a unpack. Por ejemplo, socket.ntohl() requiere un int, y int() no convertirá una cadena de datos binarios.

¡Gracias por sus sugerencias!

+0

¿Qué está desempacando exactamente? ¿Es simplemente una matriz uniforme de valores numéricos? –

+0

Desafortunadamente es una secuencia mixta de singletons, donde el contenido se indica mediante un encabezado. La mayor parte de la conversión es para enteros y flotantes 4B. – CNK

+1

caso de prueba sería bueno aquí – Triptych

Respuesta

2

El problema de velocidad probablemente no proviene de la implementación del propio struct.unpack_from(), sino que en todo lo demás Python necesita hacer — búsquedas de diccionario, crear objetos, funciones de llamada y otras tareas. Puede acelerar las cosas muy ligeramente mediante la eliminación de una de estas búsquedas de diccionario mediante la importación de unpack_from directamente en lugar de obtenerlo desde el módulo struct cada vez:

$ python -m timeit -s "import struct; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = struct.unpack_from('>I', network_stream, 0)" 
1000000 loops, best of 3: 0.277 usec per loop 

$ python -m timeit -s "import struct; from struct import unpack_from; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = unpack_from('>I', network_stream, 0)" 
1000000 loops, best of 3: 0.258 usec per loop 

Sin embargo, si es necesario que haya una gran cantidad de lógica de análisis que necesita desempaquetar un número a la vez, y evitará que desempaque una gran cantidad de datos al por mayor, no importa cómo llame para hacerlo por usted. Probablemente va a necesitar hacer todo este ciclo interno en un lenguaje con menos sobrecarga, como C.

+0

Pensamiento interesante. De hecho, utilicé 'from struct import *'. Convirtió esto para imitar su ejemplo y también encontró una diferencia de rendimiento del 5% en aproximadamente 220 millones de llamadas. Nunca hubiera esperado eso. ¡Gracias! – CNK

2

Basado en mi experiencia, estás en lo correcto que tendrá que ser trasladado a C. Como el código que has descubierto el funcionamiento de las diversas herramientas para la conversión binaria (struct y ctypes por ejemplo) tienen un rendimiento más o menos similar .

Cython es la manera más fácil de generar una extensión C para Python.

Otro enfoque fácil es abandonar CPython completamente a favor de pypy que puede generar código de bajo nivel de alta calidad utilizando su JIT de rastreo.

Un enfoque más desafiante pero más directo es escribir una extensión C simple. Esto no es divertido, pero no es difícil.

+0

¿Cuál de estos métodos estimaría tener la sobrecarga de llamada más baja? ¿La extensión C va a ser más eficiente que usar ctypes? – CNK

+1

La extensión C siempre puede ganar porque tiene la posibilidad de hacer muchas conversiones a la vez (por devolver los números en una lista o en un iterador). El enfoque * ctypes * tiene una granularidad de una llamada por conversión. Además, no quiere * todos * los datos, por lo que una extensión C puede omitir valores no deseados, ahorrando muchos ciclos de conversión/asignación/incremento/comparación/salto/decremento. –