Pregunta

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

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

la velocidad es realmente sorprendente, la velocidad es cercana a la del código nativo.¿Cómo pueden hacer eso?Ellos dijeron eso:

P.¿NMath es .NET "puro"?

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

¿Alguien puede explicarme más?

¿Fue útil?

Solución

El punto sobre C ++ / CLI es correcta. Para completar el cuadro, a sólo dos puntos interesantes adicionales:

  • .NET gestión de memoria (recolector de basura), obviamente, no es el problema aquí, como NMath todavía depende de ella

  • La ventaja de rendimiento es en realidad proporcionada por Intel MKL, que ofrece implementaciones extremadamente optimizados para muchas CPU. Desde mi punto de vista, este es el punto crucial. El uso sencillo, naiv código C / C ++ suele necesariamente le dan un rendimiento superior sobre C # /. NET, a veces es incluso peor. Sin embargo C ++ / CLI le permite explotar todas las opciones de optimización "sucias".

Otros consejos

  

¿Cómo pueden hacer eso?

Al igual que la mayoría de las bibliotecas numéricas para .NET, NMath es poco más que un envoltorio sobre una MKL de Intel incrustado en el ensamblado de .NET, probablemente mediante la vinculación con C ++ / CLI para crear un montaje mixto . Puede que acabe de Benchmarked los bits que en realidad no son escritas en .NET.

Los artículos F # .NET Journal numéricos Bibliotecas: 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 un poco de funcionalidad y NMath era en realidad la más lenta de todas las bibliotecas comerciales. Su PRNG fue más lento que todos los demás y un 50% más lento que la biblioteca Math.NET libre, algunas funciones básicas que faltaba (por ejemplo, la capacidad de calcular Gamma(-0.5)) y otra funcionalidad básica (las funciones relacionadas con el Gamma no proporcionan) estaba roto. Tanto la optimización extrema y Bluebit golpearon NMath en el punto de referencia eigensolver. NMath ni siquiera proporcionar una transformada de Fourier en el momento.

Aún más sorprendente, las discrepancias de rendimiento a veces eran enormes. El más caro de la biblioteca numérica comercial que probamos (IMSL) era más de 500 × más lenta que la biblioteca FFTW gratuita en el punto de referencia de FFT y no de las bibliotecas hecho ningún uso de múltiples núcleos en el momento.

De hecho, fue precisamente la mala calidad de estas bibliotecas que nos animaron a comercializar nuestra propia rel="noreferrer"> biblioteca (que es 100% puro # código F).

Soy uno de los principales desarrolladores de ILNumerics . Así que soy parcial, obviamente;) Pero estamos más revelación de información sobre nuestros internos, así que voy a dar algunas ideas sobre nuestros de velocidad 'secretos'.

Todo depende de cómo se utilizan los recursos del sistema! Si está a punto de velocidad pura y la necesidad de manejar grandes conjuntos, que se asegurará de que (ordenados por orden de importancia, lo más importante primero)

  1. Administrar la memoria apropiada! gestión de memoria 'ingenuo' dará lugar a un mal desempeño, ya que hace hincapié en la GC mal, provoca la fragmentación de memoria y degrada la localidad de memoria (por lo tanto el rendimiento de caché). En un entorno de recogida de basura como .NET, esto se reduce a la prevención de las asignaciones de memoria frecuentes. En ILNumerics, se implementó un banco de memoria de alto rendimiento con el fin de archieve este objetivo (y eliminación determinista de matrices temporales para conseguir una buena sintaxis, la semántica de función cómoda sin torpes).

  2. Utilizar el paralelismo! Esto apunta a los dos: hilo nivel paralelismo y nivel de datos paralelismo. Múltiples núcleos son utilizados por el roscado de cálculo partes intensivas de cálculo. En X86 / X64 CPU SIMD extensions / multimedia como SSE.XX y AVX permitir que una pequeña pero efectiva vectorización. Ellos no son direccionables directamente por los lenguajes .NET actuales. Y esta es la única razón, ¿por qué MKL puede es aún más rápido que el código de .NET 'puro'. (Sin embargo, las soluciones ya están subiendo.)

  3. Para archieve la velocidad de idiomas altamente optimizados como FORTRAN y C ++, las mismas optimizaciones deben obtener aplicado a su código como se ha hecho para ellos. C # ofrece la opción de no hacerlo.

Tenga en cuenta, estas precauciones se deben seguir en ese orden! No tiene sentido preocuparse por las extensiones SSE o incluso la eliminación de verificación límite, si el cuello de botella es el ancho de banda de memoria y el procesador (s) pasan la mayor parte del tiempo de espera de nuevos datos. Además, para muchas operaciones simples que ni siquiera paga de invertir grandes esfuerzos para archieve la última escala pequeña hasta el máximo rendimiento! Considere el ejemplo común de la función DAXPY LAPACK. Añade los elementos de un vector X para el elemento correspondiente de otro vector Y. Si esto se hace por primera vez, toda la memoria para X e Y tendrá que llegar obtienen de la memoria principal. Hay poco o nada se puede hacer al respecto. Y la memoria es el cuello de botella! Así que sin importar si la adición al final se hace de la manera ingenua en C #

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

o hecho mediante el uso de estrategias de vectorización - que tendrá que esperar a que la memoria!

Lo sé, esta respuesta hace algún modo "sobre las respuestas de la pregunta, ya que la mayoría de estas estrategias se utilizan actualmente no del producto mencionado (¿todavía?). Siguiendo ver estos puntos, que con el tiempo se terminará con un rendimiento mucho mejor que cualquier aplicación ingenua en un lenguaje 'nativo'.

Si está interesado, puede revelar su aplicación de L-BFGS? Voy a ser feliz para convertirlo en ILNumerics y publicar resultados de la comparación y estoy seguro, otras bibliotecas enumeradas aquí les gustaría seguir. (?)

He publicado un blog artículo abordar esta cuestión .

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

Hoy en día, es un estándar de la industria crear bibliotecas mixtas .Net/nativa para aprovechar las ventajas de ambas plataformas para optimizar el rendimiento.No sólo NMath, muchas bibliotecas comerciales y gratuitas con interfaz .net funcionan así.Por ejemplo:Numéricos Math.NET, dnanalítica, Optimización extrema, FinMath y muchos otros.La integración con MKL es extremadamente popular para las bibliotecas numéricas .net, y la mayoría de ellas simplemente usan el ensamblado Managed C++ como 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 su compatibilidad; necesita tener dlls del kernel de C++ administrados en gran medida para el modo de 32 bits y 64 bits.

  3. Las llamadas administradas de forma nativa necesitan realizar una clasificación que ralentiza el rendimiento de operaciones rápidas llamadas con frecuencia, como Gamma o NormalCDF.

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

Desde el (nativo) de Intel MKL está haciendo las cuentas, en realidad estás no hacer los cálculos en código administrado. Estás simplemente usando el administrador de memoria de .Net, por lo que los resultados son utilizados fácilmente por código .Net.

He aprendido comentario de forma más @Darin Dimitrov a su respuesta y comentario de @Trevor Misfeldt a @ comentario de Darin. Por lo tanto, la publicación como una respuesta, para los futuros lectores.

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

La tiempo se dedica en métodos de descomposición en el interior de MKL de Intel . Prohibida la reproducción de los datos se requiere , tampoco. Por lo tanto, no es una cuestión de si la CLI es rápido o no. Se trata de que la ejecución se produce .

Además @ blog de Pablo es también una buena lectura. Aquí está el resumen.

C # es rápida, asignación de memoria que no es. Reutilización de las variables como referencia o fuera parámetros , en lugar de devolver las nuevas variables a partir de métodos. La asignación de una nueva variable consume memoria y ralentiza la ejecución. @Haymo Kutschbach ha explicado este pozo.

Si la precisión no es necesario, la ganancia de rendimiento en el cambio de doble precisión simple es considerable (por no hablar de la memoria de ahorro para el almacenamiento de datos).

Para muchos cálculos cortos, para llamar a un C ++ / rutina CLI desde C #, fijando todos los punteros a los datos asignados en el espacio administrado, y luego llamar a la biblioteca de Intel es generalmente mejor que utilizar P / Invoke para llamar a la biblioteca directamente desde C # , debido al coste de cálculo de referencias de los datos. Según lo mencionado por @Haymo Kutschbach en los comentarios, para este tipo de blittable Sin embargo, no hay diferencia entre C ++ / CLI y C #. Arreglos de tipos y clases blittable que contienen sólo los miembros blittable están puestas 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 tipos de blittable y no blittable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top