A linguagem C ++ fornece programação genérica e metaprogramação por meio de modelos. Essas técnicas chegaram a muitos pacotes de computação científica em larga escala (por exemplo, MPQC , LAMMPS , CGAL , Trilinos ). Mas o que eles realmente contribuíram para a computação científica em valor que vai além de linguagens não genéricas e não meta, como C ou Fortran, em termos de tempo geral de desenvolvimento e usabilidade, para uma eficiência igual ou adequada?
Dada uma tarefa de computação científica, a programação genérica e a metaprogramação por meio de modelos C ++ demonstraram uma melhoria na produtividade, expressividade ou usabilidade medida por quaisquer parâmetros de referência bem compreendidos (linhas de código, esforço pessoal, etc ...)? Da mesma forma, quais riscos estão associados ao uso de modelos C ++ para genéricos e metaprogramação?
fonte
Respostas:
Penso que, em geral, a metaprogramação de modelos foi considerada inutilizável na prática - compila muito lentamente e as mensagens de erro que recebemos são impossíveis de decifrar. A barreira de entrada para os recém-chegados também é muito alta ao usar a metaprogramação.
É claro que a programação genérica é uma questão totalmente diferente, como testemunhado por Trilinos, deal.II (minha própria biblioteca), DUNE e muitas outras bibliotecas - expressar o mesmo conceito operando em diferentes tipos de dados é um acéfalo, e a comunidade o aceitou amplamente desde que permaneça dentro dos limites que evitam os problemas da metaprogramação. Eu acho que a programação genérica se qualifica como um sucesso óbvio.
Obviamente, nenhum desses tópicos é imediatamente conectado ao POO. OOP, novamente, eu diria, universalmente aceito pela comunidade científica da computação. Ainda menos que a programação genérica, não é um tópico de debate: toda biblioteca de sucesso escrita nos últimos 15 anos (seja em C ++, C ou Fortran) usa técnicas de POO.
fonte
Deixe-me dar um exemplo baseado na experiência. A maioria das bibliotecas que uso diariamente usa o OOP de alguma forma. OOP é capaz de esconder a complexidade necessária para muitos domínios, não é um mecanismo que realmente ajuda no desempenho. O que pode acontecer é que uma biblioteca é capaz de usar otimizações específicas com base na hierarquia de objetos, mas a maior parte é sobre ocultar a complexidade do usuário. Pesquise os Padrões de Design, eles são os mecanismos frequentemente empregados para realizar essa ocultação de complexidade.
Tome o PETSc como exemplo. O PETSc usa um modelo inspetor / executor de OOP, em que qualquer um de seus algoritmos analisa as rotinas disponíveis em um determinado objeto e escolhe o que executar para realizar a rotina. Isso permite que o usuário separe preocupações, por exemplo, a ação da matriz pode incluir qualquer tipo de rotina bloqueada ou otimizada e ser efetivamente usada por vários solucionadores iterativos. Ao dar ao usuário a capacidade de especificar seus próprios tipos de dados e avaliações, eles recebem algumas rotinas importantes e também têm toda a funcionalidade da biblioteca ainda disponível.
Outro exemplo que darei é FEniCS e deal.II. Ambas as bibliotecas usam OOP para generalizar um grande número de métodos de elementos finitos. Em tudo, desde o tipo de elemento, a ordem dos elementos, a representação em quadratura e assim por diante, é intercambiável. Embora essas duas bibliotecas sejam "mais lentas" do que alguns códigos FEM estruturados para fins especiais, eles podem resolver uma ampla variedade de problemas com grande parte da complexidade do FEM desconhecida pelo usuário.
Meu exemplo final é Elemental. Elemental é uma nova biblioteca de álgebra linear densa que levou a dificuldade de gerenciar comunicadores MPI e localização de dados para uma construção de linguagem muito simples. O resultado é que, se você tiver um código de série FLAME, alterando os tipos de dados, também poderá ter um código paralelo via Elemental. Ainda mais interessante, você pode brincar com a distribuição de dados configurando uma distribuição igual a outra.
OOP deve ser pensado como uma maneira de gerenciar a complexidade, não um paradigma para competir com a montagem enrolada manualmente. Se o fizer mal, resultará em muita sobrecarga, portanto, é preciso manter o tempo e atualizar os mecanismos com os quais eles a usam.
fonte
O que os recursos de linguagem
OOP
fazem para a computação científica são declarações de código mais compactas, o que ajuda a entender e usar melhor o código. Por exemplo, asFFT
rotinas precisam conter um grande número de argumentos para cada chamada de função, tornando o código complicado.Usando
module
ouclass
declarações, apenas o que é necessário no momento da chamada pode ser passado, pois o restante dos argumentos pertence à configuração do problema (ou seja, tamanho das matrizes e coeficientes).Na minha experiência, recebi
SUBROUTINE
ligações com 55 argumentos (entrada e saída) e reduzi para 5, tornando o código melhor.Isso é valor.
fonte
Sou um forte defensor da programação genérica e da metaprogramação para computação científica. Na verdade, estou desenvolvendo uma biblioteca C ++ de software livre para métodos Galerkin, com base nessas técnicas, chamada Feel ++ (http://www.feelpp.org), que está cada vez mais ganhando força. É verdade que ainda existem dificuldades como tempos de compilação lentos e que a curva de aprendizado pode ser acentuada se alguém quiser entender o que está acontecendo nos bastidores. No entanto, isso é extremamente interessante e alucinante. Se feito no nível da biblioteca e ocultando a complexidade por trás de uma linguagem específica de domínio, você obtém uma ferramenta extremamente poderosa. Temos à nossa disposição uma ampla variedade de métodos para usar e comparar. Para o ensino da computação científica, isso é incrível, também para pesquisas e novos métodos numéricos, para aplicativos de grande escala, bem, nós trabalhamos nisso, mas até agora tudo bem, já podemos fazer algumas coisas legais. Temos engenheiros, físicos e matemáticos usando: a maioria deles apenas usa a linguagem para formulação variacional e está feliz com isso. Olhando para algumas das formulações que nossos colegas físicos manipulam, eu não gostaria de vê-las feitas "à mão" sem uma linguagem de alto nível para descrever a formulação variacional. Pessoalmente, considero que essas "técnicas" ou "paradigmas" agora são necessárias para lidar com a complexidade do código de computação científica, tendo que multiplicar o tamanho do código por um grande fator. Provavelmente, é necessário melhorar o suporte à metaprogramação em C ++, mas ele já está em boa forma, especialmente desde o C ++ 11.
fonte
Você pode encontrar o artigo http://arxiv.org/abs/1104.1729 relevante para sua pergunta. Ele discute modelos de expressão (uma aplicação específica da meta-programação de modelos usada no código científico) da perspectiva do desempenho.
fonte
Os modelos são muito bons na remoção de verificações de tipo / domínio em tempo de execução. Eles podem ser resolvidos no momento da compilação. Em teoria, isso pode aumentar o desempenho sobre o mesmo tipo de implementação em C ou Fortran, onde a verificação de tipo só pode ser feita em tempo de execução - as verificações são implementadas no código-fonte. No entanto, você pode obter os mesmos resultados em C usando as opções de pré-compilador, mas elas precisam ser feitas manualmente, diferentemente dos modelos.
No entanto, os modelos também podem gerar uma sobrecarga significativa. Geralmente, eles podem criar inchaço no código, o que pode afetar o uso do cache de instruções. Além disso, abordagens genéricas geralmente podem atrapalhar o compilador durante a otimização - nem sempre é fácil para a análise de código quando se usa abordagens genéricas. Sempre existe um problema com a automação - incluindo a otimização do compilador - muitas vezes o código de saída não é compatível com o cache.
Os benefícios da verificação de tipo / domínio, embora certamente mais seguros, são os únicos benefícios reais que posso ver em termos de desempenho e, geralmente, são imperceptíveis. Mas, como eu disse, o efeito geral pode ser negativo dependendo do que você está fazendo. É por isso que geralmente é melhor otimizar manualmente seu código onde você tem gargalos significativos.
fonte