python - ¿Qué cambia cuando tu entrada tiene un tamaño de giga/terabyte?
large-data-volumes scientific-computing (4)
Acabo de dar mi primer paso de bebé hoy a la computación científica real hoy cuando me mostraron un conjunto de datos donde el archivo más pequeño tiene 48000 campos por 1600 filas (haplotipos para varias personas, para el cromosoma 22). Y esto se considera minúsculo.
Escribo Python, así que pasé las últimas horas leyendo sobre HDF5, y Numpy, y PyTable, pero sigo sintiendo que no estoy tratando de comprender lo que un conjunto de datos del tamaño de un terabyte realmente significa para mí como programador.
Por ejemplo, alguien señaló que con conjuntos de datos más grandes, resulta imposible leer todo el contenido en la memoria, no porque la máquina no tenga suficiente RAM, sino porque la arquitectura no tiene suficiente espacio de direcciones. Me quedé boquiabierto.
¿En qué otras suposiciones he confiado en el aula que simplemente no funcionan con aportaciones tan grandes? ¿Qué tipo de cosas necesito para comenzar a hacer o pensar de manera diferente? (Esto no tiene que ser específico de Python.)
Actualmente me dedico a la computación de alto rendimiento en un pequeño rincón de la industria petrolera y trabajo regularmente con conjuntos de datos de las órdenes de magnitud que le preocupan. Aquí hay algunos puntos a considerar:
Las bases de datos no tienen mucha tracción en este dominio. Casi todos nuestros datos se guardan en archivos, algunos de ellos se basan en formatos de archivo de cinta diseñados en los años 70. Creo que parte de la razón por la que no se utilizan las bases de datos es histórica; 10, incluso hace 5 años, creo que Oracle y sus parientes simplemente no estaban en la tarea de administrar conjuntos de datos individuales de O (TB) y mucho menos una base de datos de miles de dichos conjuntos de datos.
Otra razón es una discrepancia conceptual entre las reglas de normalización para el análisis y diseño efectivo de la base de datos y la naturaleza de los conjuntos de datos científicos.
Creo (aunque no estoy seguro) que las razones de rendimiento son mucho menos persuasivas en la actualidad. Y la razón de la falta de coincidencia de conceptos probablemente también sea menos apremiante ahora que la mayoría de las principales bases de datos disponibles pueden hacer frente a conjuntos de datos espaciales que generalmente son un ajuste conceptual mucho más cercano a otros conjuntos de datos científicos. He visto un uso cada vez mayor de las bases de datos para almacenar metadatos, con algún tipo de referencia, luego, al archivo (s) que contiene los datos del sensor.
Sin embargo, todavía estaría mirando, de hecho estoy mirando, HDF5. Tiene un par de atracciones para mí (a) es solo otro formato de archivo, así que no tengo que instalar un DBMS y luchar con sus complejidades, y (b) con el hardware adecuado puedo leer / escribir un archivo HDF5 en paralelo . (Sí, sé que también puedo leer y escribir bases de datos en paralelo).
Lo que me lleva al segundo punto: cuando se trata de conjuntos de datos muy grandes, realmente necesita estar pensando en usar computación paralela. Trabajo principalmente en Fortran, uno de sus puntos fuertes es su sintaxis de arreglo que se ajusta muy bien a una gran cantidad de computación científica; otro es el buen soporte para la paralelización disponible. Creo que Python también tiene todo tipo de soporte de paralelización, así que probablemente no sea una mala elección para ti.
Claro que puede agregar paralelismo a los sistemas secuenciales, pero es mucho mejor comenzar a diseñar para el paralelismo. Para tomar solo un ejemplo: el mejor algoritmo secuencial para un problema a menudo no es el mejor candidato para la paralelización. Es posible que esté mejor usando un algoritmo diferente, uno que se adapte mejor a múltiples procesadores. Lo que lleva perfectamente al siguiente punto.
También creo que es posible que tenga que aceptar renunciar a los archivos adjuntos que tiene (si los tiene) a muchos algoritmos inteligentes y estructuras de datos que funcionan bien cuando todos sus datos residen en la memoria. Muy a menudo, tratar de adaptarlos a la situación en la que no puede obtener los datos en la memoria de una vez, es mucho más difícil (y menos eficaz) que la fuerza bruta y considera el archivo completo como una gran matriz.
El rendimiento comienza a importar de manera seria, tanto el rendimiento de ejecución de los programas como el rendimiento del desarrollador. No es que un conjunto de datos de 1TB requiera 10 veces más código que un conjunto de datos de 1GB, por lo que debe trabajar más rápido, sino que algunas de las ideas que necesitará implementar serán locamente complejas y probablemente tengan que ser escritas por especialistas en dominios. Es decir, los científicos con los que estás trabajando. Aquí los especialistas del dominio escriben en Matlab.
Pero esto está pasando demasiado tiempo, es mejor que vuelva a trabajar
En pocas palabras, las principales diferencias de la OMI:
- Debe saber de antemano cuál será su posible cuello de botella (E / S o CPU) y concentrarse en el mejor algoritmo e infraestructura para solucionarlo. I / O con bastante frecuencia es el cuello de botella.
- La elección y el ajuste fino de un algoritmo a menudo dominan cualquier otra elección realizada.
- Incluso cambios modestos en los algoritmos y patrones de acceso pueden afectar el rendimiento en órdenes de magnitud. Estarás micro-optimizando mucho. La "mejor" solución dependerá del sistema.
- Hable con sus colegas y otros científicos para aprovechar sus experiencias con estos conjuntos de datos. Muchos trucos no se pueden encontrar en los libros de texto.
- La pre-computación y el almacenamiento pueden ser extremadamente exitosos.
Ancho de banda y E / S
Inicialmente, el ancho de banda y la E / S a menudo son el cuello de botella. Para darle una perspectiva: en el límite teórico de SATA 3 , se tarda unos 30 minutos en leer 1 TB. Si necesita acceso aleatorio, leer varias veces o escribir, desea hacerlo en la memoria la mayor parte del tiempo o necesita algo sustancialmente más rápido (por ejemplo, iSCSI con InfiniBand ). Su sistema idealmente debería ser capaz de hacer E / S paralelas para acercarse lo más posible al límite teórico de cualquier interfaz que esté utilizando. Por ejemplo, simplemente acceder a diferentes archivos en paralelo en diferentes procesos, o HDF5 sobre MPI-2 I / O es bastante común. Idealmente, también realiza el cálculo y la E / S en paralelo para que uno de los dos sea "gratis".
Agrupaciones
Dependiendo de su caso, la E / S o la CPU pueden ser el cuello de botella. No importa cuál sea, se pueden lograr enormes aumentos de rendimiento con los clústeres si puede distribuir sus tareas de manera efectiva (por ejemplo, MapReduce ). Esto podría requerir algoritmos totalmente diferentes a los ejemplos típicos de libros de texto. Pasar tiempo de desarrollo aquí es a menudo el mejor tiempo empleado.
Algoritmos
Al elegir entre los algoritmos, la O grande de un algoritmo es muy importante, pero los algoritmos con una O grande similar pueden ser dramáticamente diferentes en rendimiento dependiendo de la localidad. Cuanto menos local sea un algoritmo (es decir, cuanto más falte la memoria caché y la memoria principal), peor será el rendimiento: el acceso al almacenamiento suele ser un orden de magnitud más lento que el de la memoria principal. Los ejemplos clásicos de mejoras serían el tiling para las multiplicaciones de matriz o el intercambio de bucles .
Computadora, lenguaje, herramientas especializadas
Si su cuello de botella es de E / S, esto significa que los algoritmos para grandes conjuntos de datos pueden beneficiarse de más memoria principal (por ejemplo, 64 bits) o lenguajes de programación / estructuras de datos con menos consumo de memoria (por ejemplo, en Python __slots__
podría ser útil), porque más la memoria puede significar menos E / S por tiempo de CPU. Por cierto, los sistemas con TB de memoria principal no son desconocidos (p. Ej., Superdomes HP ).
De manera similar, si su cuello de botella es la CPU, las máquinas, los lenguajes y los compiladores más rápidos que le permiten usar características especiales de una arquitectura (por ejemplo, SIMD como SSE ) podrían aumentar el rendimiento en un orden de magnitud.
La forma en que encuentre y acceda a los datos y almacene la metainformación puede ser muy importante para el rendimiento. A menudo, utilizará archivos planos o paquetes no estándar específicos del dominio para almacenar datos (por ejemplo, no un db relacional directamente) que le permitan acceder a los datos de manera más eficiente. Por ejemplo, kdb+ es una base de datos especializada para grandes series de tiempo, y ROOT usa un objeto TTree
para acceder a los datos de manera eficiente. Las pyTables que mencionas serían otro ejemplo.
Las principales suposiciones se refieren a la cantidad de cpu / cache / ram / storage / ancho de banda que puede tener en una sola máquina a un precio aceptable. Hay muchas respuestas aquí en que aún se basan en los supuestos anteriores de una máquina de 32 bits con 4G de RAM y alrededor de un terabyte de almacenamiento y una red de 1Gb. Con módulos de RAM DDR-3 de 16 GB a 220 Eur, 512 GB de RAM, se pueden construir 48 máquinas centrales a precios razonables. El cambio de discos duros a SSD es otro cambio importante.
Si bien algunos idiomas tienen una sobrecarga de memoria más baja en su tipo que en otros, eso realmente no importa para datos de este tamaño, no está guardando todo su conjunto de datos en la memoria, independientemente del idioma que esté usando, por lo que el "gasto" De Python es irrelevante aquí. Como señaló, simplemente no hay suficiente espacio de direcciones para siquiera hacer referencia a todos estos datos, y mucho menos aferrarse a ellos.
Lo que esto significa normalmente es a) almacenar sus datos en una base de datos, o b) agregar recursos en forma de computadoras adicionales, agregando así a su memoria y espacio de direcciones disponibles. De manera realista vas a terminar haciendo estas dos cosas. Una cosa clave que debe tener en cuenta al usar una base de datos es que una base de datos no es solo un lugar para colocar sus datos mientras no la usa, puede hacer TRABAJO en la base de datos, y debe tratar de hacerlo. La tecnología de base de datos que utiliza tiene un gran impacto en el tipo de trabajo que puede hacer, pero una base de datos SQL, por ejemplo, está bien adaptada para realizar muchas tareas matemáticas y hacerlo de manera eficiente (por supuesto, esto significa que el diseño del esquema se convierte en una parte muy importante de su arquitectura en general). No solo extraiga los datos y manipúlelos solo en la memoria: intente aprovechar las capacidades de consulta computacional de su base de datos para realizar el mayor trabajo posible antes de poner los datos en la memoria de su proceso.