Pergunta

Na minha experiência, .NET é 2 a 3 vezes mais lento do que o código nativo. (I implementado L-BFGS para otimização multivariada).

tracei os anúncios em stackoverflow para http://www.centerspace.net/products/

a velocidade é realmente incrível, a velocidade está perto de código nativo. Como eles podem fazer isso? Eles disseram que:

Q. É NMath "puro" .NET?

A. A resposta depende um pouco da sua definição de ".NET pura". NMath é escrito em C #, além de uma pequena camada Dirigido C ++. Para um melhor desempenho das operações básicas de álgebra linear, no entanto, NMath se baseia na Intel Math Kernel Biblioteca nativa (incluído com NMath). Mas não existem componentes COM, sem DLLs - apenas conjuntos .NET. Além disso, toda a memória alocada no ++ camada C geridos e utilizados por código nativo é alocada a partir do heap gerenciado.

Alguém pode explicar mais para mim?

Foi útil?

Solução

O ponto sobre C ++ / CLI está correto. Para completar o quadro, a apenas dois pontos interessantes adicionais:

  • .NET gerenciamento de memória (coletor de lixo), obviamente, não é o problema aqui, como NMath ainda depende it

  • A vantagem de desempenho é realmente fornecido pela Intel MKL, que oferece implementações extremamente otimizado para muitas CPUs. Do meu ponto de vista, este é o ponto crucial. Usando direto, naiv código C / C ++ não vai necessariamente dar-lhe um desempenho superior sobre C # /. NET, às vezes é ainda pior. No entanto C ++ / CLI permite explorar todas as "sujas" opções de otimização.

Outras dicas

Como eles podem fazer isso?

Como a maioria das bibliotecas numéricos para .NET, NMath é pouco mais que um wrapper sobre um processador Intel MKL embutido no .NET assembly, provavelmente por ligação com C ++ / CLI para criar um mista montagem . Você provavelmente apenas aferido os bits que não são realmente escritas em .NET.

Os artigos F # .NET Jornal numéricos Bibliotecas: funções especiais, números de interpolação e aleatórios (16 de março de 2008) e numérica bibliotecas: álgebra linear e métodos espectrais (16 de Abril de 2008) testou um pouco de funcionalidade e NMath era realmente o mais lento de todas as bibliotecas comerciais. A sua PRNG foi mais lento do que todos os outros e 50% mais lenta do que a biblioteca Math.NET livre, algumas funcionalidades básica foi ausente (por exemplo, a capacidade de calcular Gamma(-0.5)) e outras funcionalidades de base (as funções Gamma-relacionados que proporcionam) foi quebrado. Ambos extrema Optimization e Bluebit bater NMath na referência eigensolver. NMath nem sequer fornecer uma Transformada de Fourier no momento.

Ainda mais surpreendente, as discrepâncias de desempenho foram, por vezes enorme. A biblioteca mais caro comercial numérica testamos (IMSL) foi mais de 500 × mais lento do que a biblioteca FFTW livre na referência FFT e nenhum das bibliotecas feito qualquer uso de múltiplos núcleos no momento.

Na verdade, foi precisamente a má qualidade dessas bibliotecas que nos incentivou a comercializar o nosso próprio rel="noreferrer"> biblioteca (que é 100% puro F # código).

Eu sou um dos principais desenvolvedores de ILNumerics . Então, eu sou preconceituoso, obviamente;) Mas nós estamos mais divulgados a respeito de nossos internos, por isso vou dar alguns insights sobre nosso velocidade 'segredos'.

Tudo depende de como os recursos do sistema são utilizados! Se você está prestes a velocidade pura e necessidade de lidar com grandes matrizes, você irá certificar-se (ordenados por importância, mais importante primeiro)

  1. Gerenciar sua memória de forma adequada! gerenciamento de memória 'Naive' vai levar ao mau desempenho, uma vez que salienta a GC mal, provoca a fragmentação da memória e localidade memória degrada (daí o desempenho do cache). Em um ambiente recolhido lixo como .NET, isso se resume a prevenção de alocações de memória frequentes. Em ILNumerics, implementamos um pool de memória de alto desempenho, a fim de archieve este objetivo (e eliminação determinista de matrizes temporárias para obter um bom, sintaxe confortável sem semântica função desajeitados).

  2. Utilize o paralelismo! Este alvos ambos: Linha nível de paralelismo e paralelismo nível de dados. Vários núcleos são utilizados por computação rosqueamento partes intensivos de cálculo. Em X86 / X64 CPUs SIMD / extensões multimídia como SSE.XX e AVX permitir que uma pequena mas eficaz vetorização. Eles não são directamente endereçável por linguagens atuais .NET. E esta é a única razão, porque MKL podem ainda é mais rápido do que 'puro' código .NET. (Mas as soluções já estão subindo.)

  3. Para archieve o velocidade de línguas altamente otimizados como Fortran e C ++, as mesmas otimizações deve obter aplicado ao seu código como feito por eles. C # oferece a opção fazer isso.

Note, estas precauções devem ser seguidas nessa ordem! Não faz sentido se preocupar com extensões SSE ou mesmo a remoção de verificação limite, se o gargalo é a largura de banda de memória e o processador (s) passam a maior parte do tempo à espera de novos dados. Além disso, para muitas operações simples que nem sequer paga de investir enormes esforços para archieve a última escala pequena até o máximo desempenho! Considere o exemplo comum da função LAPACK DAXPY. Acrescenta os elementos de um vector X ao elemento correspondente de outra Y. vector Se isso for feito, pela primeira vez, toda a memória para X e Y terá que obter obtido a partir da memória principal. Há pouco a nada que você possa fazer sobre isso. E a memória é o gargalo! Portanto, independentemente se a adição no final é feito da maneira ingênua em C #

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

ou feito por meio de estratégias de vectorização - ele vai ter que esperar para a memória!

Eu sei, esta resposta faz de alguma forma 'mais respostas' a questão, uma vez que a maioria destas estratégias atualmente não são utilizados a partir do produto mencionado (ainda?). Seguindo pontos thoses, você acabaria por acabar com um desempenho muito melhor do que qualquer implementação ingênua em uma linguagem 'nativa'.

Se você está interessado, você pode divulgar sua implementação do L-BFGS? Eu vou ser feliz para convertê-lo para ILNumerics e resultados de comparação post e estou certo, outras bibliotecas listadas aqui gostaria de seguir. (?)

Eu publiquei um blog artigo abordar esta questão .

A chave é C ++ / CLI . Ele permite que você compilar o código C ++ em um .NET conseguiu montagem.

Hoje é padrão da indústria para fazer bibliotecas mistas .Net / nativos a fim de tirar vantagens de ambas as plataformas para otimização de desempenho. Não só NMath, muitas bibliotecas comerciais e gratuitos com .net interface de trabalho como este. Por exemplo: Math.NET Numerics, dnAnalytics , Primeiríssimo Optimization, FinMath e muitos outros. Integração com MKL é extremamente popular para .NET numérica bibliotecas, e a maior parte deles só usar Managed C ++ montagem como um nível intermédio. Mas esta solução tem uma série de inconvenientes:

  1. Intel MKL é um software proprietário e que é um pouco caro. Mas algumas bibliotecas como dnAnalytics fornece uma substituição gratuita de funcionalidade MKL com código de .net puro. Fora do curso, é muito mais lento, mas é livre e totalmente funcional.

  2. Ele reduz a sua compatibilidade você precisa ter pesado gerenciado C ++ kernel do dlls para o modo de 32 bits e 64 bits.

  3. Dirigido para chamadas nativas precisam realizar empacotamento qual o desempenho para baixo lenta de fast chamados com freqüência operações como Gamma ou normalcdf.

Os dois últimos problemas resolvidos na biblioteca RTMath FinMath. Eu realmente não sei como eles fizeram isso, mas eles fornecem única dll .net puro que compilado para qualquer plataforma CPU e suportes 32 e 64 bits. Também eu não vi qualquer degradação do desempenho contra MKL quando eu preciso chamar bilhões normalcdf vezes.

Uma vez que o (nativo) Intel MKL está fazendo as contas, você está realmente não fazer a matemática em código gerenciado. Você está apenas usando o gerenciador de memória do .net, por isso os resultados são facilmente usado pelo código .Net.

Eu aprendi o comentário de mais forma @Darin Dimitrov a sua resposta e comentário de @Trevor Misfeldt para @ o comentário de Darin. Daí publicá-la como uma resposta, para futuros leitores.

NMath usa P / Invoke ou C ++ / CLI para chamar funções nativas Intel Math Kernel Library, que é onde os cálculos mais intensivos são feitas e que é por isso que é tão rápido.

O tempo é gasto na métodos de decomposição dentro de MKL da Intel . Sem cópia de dados é necessária , qualquer um. Então, não é uma questão de saber se CLI é rápido ou não. É sobre onde a execução acontece .

Também @ Blog de Paulo é também uma boa leitura. Aqui está o resumo.

C # é rápido, alocação de memória não está. reutilizar as variáveis ??como ref ou out parâmetros , ao invés de retornar novas variáveis ??a partir de métodos. A atribuição de uma nova memória consome variáveis ??e retarda a execução. @Haymo Kutschbach explicou isso muito bem.

Se a precisão não é necessário, o ganho de desempenho na mudança de dupla de precisão simples é considerável (para não mencionar a memória poupança para o armazenamento de dados).

Para muitos cálculos curtas, para chamar a ++ / rotina cli C de C #, prendendo todos os ponteiros para dados alocados no espaço gerenciado, em seguida, chamar a biblioteca Intel é geralmente melhor do que usar P / Invoke para chamar a biblioteca diretamente do C # , devido ao custo de empacotamento dos dados. Como mencionado por @Haymo Kutschbach nos comentários, para tipos blittable no entanto, nenhuma diferença entre C ++ / CLI e C #. Matrizes de tipos blittable e classes que contêm apenas membros blittable são fixadas em vez de copiados durante o empacotamento. Consulte https://msdn.microsoft.com/en -us / library / 75dwhxf7 (v = vs.110) .aspx para uma lista de tipos blittable e não-blittable.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top