Precisão vs. Precisão
O que eu gostaria de saber é se devo usar System.currentTimeMillis () ou System.nanoTime () ao atualizar as posições do meu objeto no meu jogo? A mudança de movimento deles é diretamente proporcional ao tempo decorrido desde a última ligação e eu quero ser o mais preciso possível.
Eu li que existem alguns problemas sérios de resolução de tempo entre diferentes sistemas operacionais (ou seja, que o Mac / Linux tem uma resolução de quase 1 ms, enquanto o Windows tem uma resolução de 50ms?). Estou executando meus aplicativos principalmente no Windows e a resolução de 50ms parece bastante imprecisa.
Existem opções melhores que as duas que eu listei?
Alguma sugestão / comentário?
java
timer
time-precision
mmcdole
fonte
fonte
nanoTime
geralmente é mais preciso que o currentTimeMillis, mas também é uma ligação relativamente cara.currentTimeMillis()
executado em alguns (5-6) relógios da CPU, o nanoTime depende da arquitetura subjacente e pode ter mais de 100 relógios da CPU.System.currentTimeMillis()
: pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.htmlRespostas:
Se você está apenas procurando medições extremamente precisas do tempo decorrido , use
System.nanoTime()
.System.currentTimeMillis()
fornecerá o tempo decorrido possível mais preciso possível em milissegundos desde a época, mas forneceráSystem.nanoTime()
um tempo nanosegundo preciso, em relação a algum ponto arbitrário.Na documentação Java:
Por exemplo, para medir quanto tempo um código leva para executar:
Consulte também: JavaDoc System.nanoTime () e JavaDoc System.currentTimeMillis () para obter mais informações.
fonte
currentTimeMillis
mudar devido ao horário de verão? A opção DST não altera o número de segundos após a época. Pode ser um "relógio de parede", mas é baseado no UTC. Você deve determinar com base nas configurações de fuso horário e de horário de verão para o que isso se traduz no horário local (ou usar outros utilitários Java para fazer isso por você).Desde que mais ninguém mencionou isso ...
Não é seguro comparar os resultados de
System.nanoTime()
chamadas entre diferentes segmentos. Mesmo que os eventos dos encadeamentos ocorram em uma ordem previsível, a diferença em nanossegundos pode ser positiva ou negativa.System.currentTimeMillis()
é seguro para uso entre threads.fonte
The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
nanoTime()
diz: A mesma origem é usada por todas as chamadas deste método em uma instância de uma máquina virtual Java; outras instâncias de máquina virtual provavelmente usarão uma origem diferente. o que significa que não retornam os mesmos em threads.Atualização por Arkadiy : observei um comportamento mais correto
System.currentTimeMillis()
no Windows 7 no Oracle Java 8. O tempo foi retornado com precisão de 1 milissegundo. O código-fonte do OpenJDK não mudou, então não sei o que causa o melhor comportamento.David Holmes, da Sun, publicou um artigo no blog há alguns anos, que tem uma visão muito detalhada das APIs de tempo de Java (em particular
System.currentTimeMillis()
eSystem.nanoTime()
), quando você deseja usar quais e como elas funcionam internamente.Dentro da VM do ponto de acesso: relógios, cronômetros e eventos de agendamento - Parte I - Windows
Um aspecto muito interessante do timer usado pelo Java no Windows para APIs que possuem um parâmetro de espera temporizada é que a resolução do timer pode mudar dependendo de outras chamadas de API que tenham sido feitas - em todo o sistema (não apenas no processo específico) . Ele mostra um exemplo em que o uso
Thread.sleep()
causará essa alteração na resolução.fonte
GetSystemTimeAsFileTime
funcionou no XP vs 7. Veja aqui para mais detalhes (tl; dr ficou mais preciso, pois todo o sistema introduziu alguns métodos de tempo mais precisos).System.nanoTime()
não é suportado em JVMs mais antigas. Se isso é uma preocupação, fique comcurrentTimeMillis
Em relação à precisão, você está quase correto. Em algumas máquinas Windows,
currentTimeMillis()
tem uma resolução de cerca de 10ms (não 50ms). Não sei por que, mas algumas máquinas Windows são tão precisas quanto as máquinas Linux.Eu usei GAGETimer no passado com sucesso moderado.
fonte
Como já foi dito, currentTimeMillis é a hora do relógio, que muda devido ao horário de verão, usuários alterando as configurações de hora, segundos bissextos e sincronização da hora da Internet. Se o seu aplicativo depende do aumento monotônico dos valores de tempo decorrido, você pode preferir o nanoTime.
Você pode pensar que os jogadores não vão mexer com as configurações de tempo durante o jogo, e talvez você esteja certo. Mas não subestime a interrupção devido à sincronização da hora da Internet ou talvez a usuários de computadores remotos. A API nanoTime é imune a esse tipo de interrupção.
Se você quiser usar a hora do relógio, mas evitar descontinuidades devido à sincronização da hora da Internet, considere um cliente NTP como o Meinberg, que "ajusta" a taxa do relógio para zerá-lo, em vez de apenas redefinir o relógio periodicamente.
Eu falo por experiência própria. Em um aplicativo climático que desenvolvi, eu estava obtendo picos de velocidade do vento que ocorriam aleatoriamente. Demorou um pouco para eu perceber que minha base de tempo estava sendo interrompida pelo comportamento da hora do relógio em um PC típico. Todos os meus problemas desapareceram quando comecei a usar o nanoTime. A consistência (monotonicidade) foi mais importante para minha aplicação do que a precisão bruta ou a precisão absoluta.
fonte
System.currentTimeMillis()
relata o tempo decorrido (em milissegundos) desde a época Unix / Posix, que é Midnight, 1 de janeiro de 1970 UTC. Como o UTC nunca é ajustado para o horário de verão, esse valor não será compensado quando os fusos horários locais adicionarem ou sujeitarem deslocamentos aos horários locais para o horário de verão. Além disso, o Java Time Scale suaviza os segundos bissextos, para que os dias pareçam ter 86.400 segundos.Sim, se essa precisão for necessária
System.nanoTime()
, use , mas lembre-se de que você está exigindo uma JVM Java 5+.Nos meus sistemas XP, vejo a hora do sistema relatada em pelo menos
100 microssegundos278 nanossegundos usando o seguinte código:fonte
Para gráficos de jogos e atualizações de posição suaves, use em
System.nanoTime()
vez deSystem.currentTimeMillis()
. Eu mudei de currentTimeMillis () para nanoTime () em um jogo e obtive uma grande melhoria visual na suavidade do movimento.Embora um milissegundo possa parecer que já deveria ser preciso, visualmente não é. Os fatores que
nanoTime()
podem melhorar incluem:Como outras respostas sugerem, o nanoTime tem um custo de desempenho se chamado repetidamente - seria melhor chamá-lo apenas uma vez por quadro e usar o mesmo valor para calcular o quadro inteiro.
fonte
Eu tive uma boa experiência com nanotime . Ele fornece o tempo do relógio de parede como dois longos (segundos desde a época e nanossegundos nesse segundo), usando uma biblioteca JNI. Está disponível com a parte JNI pré-compilada para Windows e Linux.
fonte
System.currentTimeMillis()
não é seguro por tempo decorrido, porque esse método é sensível às alterações do relógio em tempo real do sistema. Você deveria usarSystem.nanoTime
. Consulte a ajuda do sistema Java:Sobre o método nanoTime:
Se você usar
System.currentTimeMillis()
o tempo decorrido, pode ser negativo (Voltar <- para o futuro)fonte
uma coisa aqui é a inconsistência do método nanoTime. ele não fornece valores muito consistentes para a mesma entrada. e, portanto, mais precisão em seu valor. portanto, sugiro que você use currentTimeMillis
fonte