velocidad test speedy movistar movil medir medidor internet gratis claro c# .net managed-c++ managed-code nmath

c# - test - La velocidad de.NET en computación numérica.



test de velocidad speedy (8)

En mi experiencia, .NET es 2 a 3 veces más lento que el código nativo. (Implementé L-BFGS para optimización multivariable).

He rastreado los anuncios en stackoverflow hasta http://www.centerspace.net/products/

La velocidad es realmente asombrosa, la velocidad es cercana al código nativo. ¿Cómo pueden hacer eso? Ellos dijeron eso:

P. ¿Es NMath "puro" .NET?

A. La respuesta depende un poco de tu definición de ".NET puro". NMath está escrito en C #, más una pequeña capa de C ++ administrado. Sin embargo, para un mejor desempeño de las operaciones básicas de álgebra lineal, NMath se basa en la biblioteca nativa de kernel de Intel (incluida con NMath). Pero no hay componentes COM, ni DLL, solo ensamblajes .NET. Además, toda la memoria asignada en la capa C ++ administrada y utilizada por el código nativo se asigna desde el montón administrado.

¿Alguien me puede explicar más?


¿Cómo pueden hacer eso?

Como la mayoría de las bibliotecas numéricas para .NET, NMath es poco más que una envoltura sobre un Intel MKL integrado en el ensamblado .NET, probablemente al vincularse con C ++ / CLI para crear un ensamblaje mixto . Probablemente acaba de realizar una prueba comparativa de los bits que no están realmente escritos en .NET.

Los artículos de la revista F # .NET Bibliotecas numéricas: funciones especiales, interpolación y números aleatorios (16 de marzo de 2008) y Bibliotecas numéricas: álgebra lineal y métodos espectrales (16 de abril de 2008) probaron bastante funcionalidad y NMath fue en realidad el más lento de todos bibliotecas comerciales. Su PRNG era más lento que todos los demás y un 50% más lento que la biblioteca Math.NET gratuita; faltaba alguna funcionalidad básica (por ejemplo, la capacidad de calcular Gamma(-0.5) ) y otra funcionalidad básica (las funciones relacionadas con Gamma que proporcionaron) fue roto. Tanto Extreme Optimization como Bluebit superaron a NMath en el punto de referencia de eigensolver. NMath ni siquiera proporcionó una Transformada de Fourier en ese momento.

Aún más sorprendente, las discrepancias en el rendimiento fueron a veces enormes. La biblioteca numérica comercial más costosa que probamos (IMSL) era 500 veces más lenta que la biblioteca FFTW gratuita en el punto de referencia de la FFT y ninguna de las bibliotecas hizo uso de múltiples núcleos en ese momento.

De hecho, fue precisamente la mala calidad de estas bibliotecas lo que nos animó a comercializar nuestra propia biblioteca F # for Numerics (que es un código F # 100% puro).


Aprendí más del comentario de @Darin Dimitrov a su respuesta y del comentario de @Trevor Misfeldt al comentario de @Darin. Por lo tanto publicarlo como una respuesta, para futuros lectores.

NMath usa P / Invoke o C ++ / CLI para llamar a las funciones nativas de Intel Math Kernel Library, que es donde se realizan los cálculos más intensivos y por eso es tan rápido.

El tiempo se gasta en métodos de descomposición dentro de MKL de Intel . Tampoco se requiere copia de datos . Por lo tanto, no se trata de si CLI es rápido o no. Se trata de donde ocurre la ejecución .

También el blog de @ Paul es también una buena lectura. Aquí está el resumen.

C # es rápido, la asignación de memoria no lo es. Reutilice las variables como parámetros de referencia o de salida , en lugar de devolver nuevas variables desde los métodos. Asignar una nueva variable consume memoria y ralentiza la ejecución. @Haymo Kutschbach lo ha explicado bien.

Si la precisión no es necesaria, la ganancia de rendimiento en el cambio de precisión doble a simple es considerable (sin mencionar el ahorro de memoria para el almacenamiento de datos).

Para muchos cálculos cortos, llamar a una rutina de C ++ / cli desde C #, fijar todos los punteros a los datos asignados en el espacio administrado, y luego llamar a la biblioteca Intel es generalmente mejor que usar P / Invoke para llamar a la biblioteca directamente desde C #, debido a El costo de ordenar los datos. Como lo mencionó @Haymo Kutschbach en los comentarios, para los tipos de blittable, sin embargo, no hay diferencia entre C ++ / CLI y C #. Las matrices de tipos y clases de blittable que contienen solo miembros de blittable se fijan en lugar de copiarse durante el cálculo de referencias. Consulte https://msdn.microsoft.com/en-us/library/75dwhxf7(v=vs.110).aspx para obtener una lista de los tipos de blittable y no blittable.


Dado que el Intel MKL (nativo) está haciendo las matemáticas, en realidad no estás haciendo las matemáticas en el código administrado. Simplemente está utilizando el administrador de memoria de .Net, por lo que los resultados son fácilmente utilizados por el código .Net.


El punto sobre C ++ / CLI es correcto. Para completar la imagen, solo dos puntos interesantes adicionales:

  • La administración de memoria .NET (recolector de basura) obviamente no es el problema aquí, ya que NMath todavía depende de ello

  • La ventaja de rendimiento es realmente proporcionada por Intel MKL, que ofrece implementaciones extremadamente optimizadas para muchas CPU. Desde mi punto de vista, este es el punto crucial. El uso directo del código C / C ++ no necesariamente le dará un rendimiento superior a C # / .NET, a veces es incluso peor. Sin embargo, C ++ / CLI le permite explotar todas las opciones de optimización "sucias".


He publicado un article blog que aborda esta pregunta.


Hoy en día, es estándar en la industria crear bibliotecas .Net / nativas mixtas para aprovechar las ventajas de ambas plataformas para la optimización del rendimiento. No solo NMath, muchas bibliotecas comerciales y gratuitas con interfaz .net que funcionan así. Por ejemplo: Math.NET Numerics, dnAnalytics , Extreme Optimization, FinMath y muchos otros. La integración con MKL es extremadamente popular para las bibliotecas numéricas .net, y la mayoría de ellas solo usan Managed C ++ como un nivel intermedio. Pero esta solución tiene una serie de inconvenientes:

  1. Intel MKL es un software propietario y es un poco caro. Pero algunas bibliotecas como dnAnalytics proporcionan un reemplazo gratuito de la funcionalidad MKL con código .net puro. Por supuesto, es mucho más lento, pero es gratuito y completamente funcional.

  2. Reduce la compatibilidad que necesita para tener archivos DLL de kernel de C ++ administrados pesados ​​tanto para el modo de 32 bits como para el de 64 bits.

  3. Las llamadas dirigidas a nativos necesitan realizar cálculos, lo que ralentiza el rendimiento de las operaciones rápidas y frecuentes, como Gamma o NormalCDF.

Los dos últimos problemas resueltos en la biblioteca RTMath FinMath. Realmente no sé cómo lo hicieron, pero proporcionan un archivo .net puro que compiló para cualquier plataforma de CPU y admite 32 bits y 64 bits. Además, no he visto ninguna degradación del rendimiento contra MKL cuando necesito llamar miles de millones a NormalCDF.


La clave es C++/CLI . Le permite compilar código C ++ en un ensamblado .NET administrado.


Soy uno de los principales desarrolladores de ILNumerics . Así que estoy predispuesto, obviamente;) Pero estamos más informados sobre nuestros aspectos internos, así que daré algunas ideas sobre nuestros "secretos" de la velocidad.

¡Todo depende de cómo se utilizan los recursos del sistema! Si se trata de velocidad pura y necesita manejar arreglos grandes, asegúrese de (ordenados por importancia, lo más importante primero)

  1. Gestiona tu memoria de forma adecuada! La administración de memoria "ingenua" conducirá a un mal rendimiento, ya que hace mucho hincapié en el GC, provoca la fragmentación de la memoria y degrada la localidad de la memoria (por lo tanto, el rendimiento de la memoria caché). En un entorno de recolección de basura como .NET, esto se reduce a evitar asignaciones de memoria frecuentes. En ILNumerics, implementamos un conjunto de memoria de alto rendimiento para archivar este objetivo (y la eliminación determinista de los arreglos temporales para obtener una sintaxis agradable y cómoda sin semántica de funciones torpes).

  2. Utiliza el paralelismo! Esto apunta tanto al paralelismo de nivel de hilo como al paralelismo de nivel de datos. Se utilizan múltiples núcleos mediante el subprocesamiento de las partes intensivas del cálculo. En las CPU X86 / X64, las extensiones SIMD / multimedia como SSE.XX y AVX permiten una vectorización pequeña pero efectiva. No son direccionables directamente por los lenguajes .NET actuales. Y esta es la única razón por la que MKL puede ser aún más rápido que el código "puro" .NET. (Pero las soluciones ya están aumentando).

  3. Para archivar la velocidad de lenguajes altamente optimizados como FORTRAN y C ++, las mismas optimizaciones deben aplicarse a su código como se hizo para ellos. C # ofrece la opción de hacerlo.

Tenga en cuenta que estas precauciones deben seguirse en ese orden! No tiene sentido preocuparse por las extensiones SSE o incluso la eliminación de cheques vinculados, si el cuello de botella es el ancho de banda de la memoria y los procesadores pasan la mayor parte del tiempo esperando nuevos datos. Además, para muchas operaciones simples, ni siquiera vale la pena invertir grandes esfuerzos para obtener la última escala minúscula hasta el máximo rendimiento. Considere el ejemplo común de la función LAPACK DAXPY. Agrega los elementos de un vector X al elemento correspondiente de otro vector Y. Si esto se hace por primera vez, toda la memoria para X e Y deberá obtenerse de la memoria principal. Hay poco o nada que puedas hacer al respecto. Y la memoria es el cuello de botella! Entonces, independientemente de si la adición al final se realiza de forma ingenua en C #

for (int i = 0; i < C.Length; i++) { C[i] = X[i] + Y[i]; }

o hecho usando estrategias de vectorización - ¡tendrá que esperar la memoria!

Lo sé, esta respuesta de alguna manera "sobre responde" a la pregunta, ya que la mayoría de estas estrategias actualmente no se utilizan a partir del producto mencionado (¿todavía?). Al seguir estos puntos, acabarías teniendo un rendimiento mucho mejor que cualquier implementación ingenua en un lenguaje "nativo".

Si está interesado, ¿podría divulgar su implementación de L-BFGS? Estaré encantado de convertirlo a ILNumerics y publicar resultados de comparación, y estoy seguro de que a las otras bibliotecas enumeradas aquí les gustaría seguir. (?)