Se o desempenho deste código é crítico, então pode fazer sentido evitar alocações de heap para Candle s. Eu acho que a maneira mais razoável de fazer isso seria fazer da Candle uma estrutura. Embora os tipos de valores mutables sejam maus. Então eu também refino a Vela para ser imutável. Isso também significa que a implementação do NewestCandle teria que mudar, provavelmente em um par de campos duplos (ou, alternativamente, uma classe mutável e reinicializável separada). Não vejo nenhum outro problema potencial de desempenho em seu código. Mas quando se trata de desempenho, você deve sempre confiar no perfil, não na intuição (ou em alguém). Além disso, não gosto de alguns nomes de seus métodos. Especificamente: ValueUpdated. Os nomes dos métodos normalmente devem estar na forma de fazer algo, não aconteceu algo. Então eu acho que um nome melhor seria UpdateValue. Adicionar. Modificar. Estas são as duas operações fundamentais do seu MovingAverage e eu acho que esses nomes não expressam bem o significado. Eu chamaria-lhes algo como MoveAndSetCurrent e SetCurrent. respectivamente. Embora tal nomeação indique que as operações fundamentais deveriam ser, em vez disso, Mover e Definir atual. Para obter um desempenho assintótico de O (n) (como a solução codificada manualmente), você poderia usar a função Agregação como em O valor acumulado (implementado Como tipo anônimo) contém dois campos: o resultado contém a compilação da lista de resultados até agora. O trabalho contém os últimos elementos do período 1. A função de agregação adiciona o valor atual à lista de trabalho, cria a média atual e adiciona-a ao resultado e, em seguida, remove o primeiro valor (ou seja, o mais antigo) da lista de trabalho. A semente (ou seja, o valor inicial para a acumulação) é compilada colocando os primeiros elementos do período 1 em Trabalhando e inicializando o Resultado em uma lista vazia. Consequentemente, a agregação começa com o período do elemento (saltando elementos (período 1) no início) Na programação funcional, este é um padrão típico de uso para a função agregada (ou dobra), btw. A solução não é funcionalmente limpa na medida em que os mesmos objetos de lista (Trabalho e Resultado) são reutilizados em cada etapa. Não tenho certeza se isso pode causar problemas se alguns compiladores futuros tentam paralizar a função Agregação automaticamente (por outro lado, eu também não tenho certeza, se isso for possível depois de tudo). Uma solução puramente funcional deve criar novas listas em cada etapa. Observe também que C não possui expressões de lista poderosas. Em algum pseudocódigo hipotético Python-C-mixed pode-se escrever a função de agregação como a qual seria um pouco mais elegante na minha humilde opinião :) Observe o tempo de execução de O (n2). Uma vez que você precisa pular mais e mais elementos em cada etapa (e afaik Skip (i) tem que chamar IEnumerator. MoveNext i times). Veja a minha resposta para uma solução no tempo O (n). (Eu apenas notei o comentário OPs abaixo que heshe possivelmente obterá os valores de um SQL DB no futuro. Neste caso, eu iria desanimar fortemente desta solução) ndash MartinStettner Mar 3 11 às 0:53 Para a maneira mais eficiente possível Para calcular uma média móvel com LINQ, você não deve usar o LINQ. Em vez disso, proponho criar uma classe auxiliar que calcula uma média móvel da maneira mais eficiente possível (usando um buffer circular e filtro médio causal), então um método de extensão para torná-lo acessível Para LINQ. Primeiro, a média móvel Esta classe fornece uma implementação muito rápida e leve de um filtro MovingAverage. Ele cria um buffer circular de Comprimento N e calcula um som, um subtrair e um multiplicar por ponto de dados anexado, em oposição ao N multiplicação por ponto para a implementação da força bruta. Os métodos de extensão acima envolvem a classe MovingAverage e permitem a inserção em um fluxo IEnumerable. Para fazer isso de uma forma mais funcional, você precisa de um método de varredura que exista no Rx, mas não no LINQ. Vamos ver como isso pareceria se você tivesse um método de varredura. Além disso, o método de varredura, tomado e ajustado a partir daqui: isso deve ter melhor desempenho do que o método de força bruta, uma vez que estamos usando um total em execução para calcular o SMA. Para começar precisamos calcular o primeiro período que chamamos de semente aqui. Então, cada valor subseqüente calculamos a partir do valor de semente acumulado. Para fazer isso, precisamos do valor antigo (isto é, t-delta) e do valor mais novo para o qual fazemos o conjunto das séries, uma vez desde o início e uma vez deslocadas pelo delta. No final, fazemos uma limpeza adicionando zeros para o comprimento do primeiro período e adicionando o valor inicial da semente. Respondeu 19 de junho às 22:58
No comments:
Post a Comment