AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79575030
Accepted
mchen
mchen
Asked: 2025-04-15 19:28:42 +0800 CST2025-04-15 19:28:42 +0800 CST 2025-04-15 19:28:42 +0800 CST

Por que System.nanoTime() acumula erros ao longo do dia?

  • 772

Estou tentando medir a latência entre meu publicador Java e um corretor de mensagens Cpp (padrão do setor).

O broker registra o horário em que recebe cada mensagem e, para o publicador Java, estou usando o seguinte código para obter registros de data e hora com precisão de microssegundos (que são gravados na mensagem de saída):

    private static final long NANOTIME_OFFSET;

    static {
        Instant instant = Instant.now();      // Get absolute time
        long nanoTime = System.nanoTime();    // Get relative time

        // Offset to convert from relative to absolute time
        NANOTIME_OFFSET = TimeUnit.SECONDS.toNanos(instant.getEpochSecond()) + instant.getNano() - nanoTime;
    }

    public static long currentTimeNanos() {
        return System.nanoTime() + NANOTIME_OFFSET;
    }

No entanto, estou percebendo que a latência medida entre o publicador e o corretor aumenta ao longo do dia e não diminui até que eu reinicie meu publicador Java.

A latência começa em <<1 ms e, de repente, salta para 500 ms. Saltos subsequentes a aproximam da marca de 1 segundo, o que é difícil de acreditar, visto que ambos os processos residem na mesma máquina.

insira a descrição da imagem aqui

A criação de perfil com o VisualVM indica que não há problemas de recursos no meu processo Java, e a captura de pacotes com o Wireshark confirma que o problema está nos registros de data e hora produzidos por currentTimeNanos().

Então por que System.nanoTime()perde precisão ao longo do dia?

Acho que a coisa correta a fazer é sempre usar Instant.now(), mas é uma chamada mais pesada que System.nanoTime()(gera um novo Instanceobjeto toda vez), então adicionaria mais sobrecarga, especialmente com um alto volume de mensagens.

Editar: Eu também acrescentaria que optei por um nanoTime()relógio baseado em -, já que Instance.now()só produzia precisão de milissegundos na minha máquina

java
  • 1 1 respostas
  • 122 Views

1 respostas

  • Voted
  1. Best Answer
    Basil Bourque
    2025-04-15T22:48:21+08:002025-04-15T22:48:21+08:00

    Nunca misture System.nanoTimecomInstant.now

    O código-fonte do OpenJDK mostra a System.nanoTimeimplementação como:

        @IntrinsicCandidate
        public static native long nanoTime();
    

    Isso significa que o método é implementado como código nativo.

    Sem nos aprofundarmos mais, sabemos que nanoTimenão usa a mesma fonte que Instant.now. A Instantclasse usa o relógio de data e hora do sistema operacional host. Em hardware de computador convencional (laptops, desktops, servidores comuns), o relógio de data e hora do sistema operacional host é resolvido em microssegundos, na melhor das hipóteses, e não em nanossegundos. Portanto, o nanoTimerecurso deve usar outra fonte para rastrear nanossegundos decorridos.

    A CPU é a fonte provável. As CPUs modernas têm uma "pulsação" regular que as mantém funcionando, cronometrando seus cálculos. Por exemplo, uma CPU de 3 GHz tem três bilhões de pulsações por segundo. Imagino que o nanoTimecódigo nativo utilize essa pulsação para contar os nanossegundos decorridos.

    A questão aqui é que essas duas fontes de tempo são completamente separadas e distintas.

    • O relógio de data e hora do sistema operacional host monitora a data e a hora. Em hardware de computador convencional, esse relógio oscila. O desvio é enorme em relação aos nanossegundos. O sistema operacional host atualiza esse relógio frequentemente após consultar um servidor de horário, localmente ou pela internet. À medida que o sistema operacional host corrige o desvio inevitável, você verá o valor do Instant.nowsalto, para frente ou para trás(!). O salto pode ser minúsculo ou grande, dependendo (a) de quanto tempo se passou desde a última correção do desvio e (b) da tendência de desvio do relógio do seu computador. (Outro problema é a precisão do seu servidor de horário.†)
    • O relógio de ciclo da CPU não sabe nada sobre calendários e relógios de parede. Este relógio só nos serve para rastrear os nanossegundos decorridos entre dois eventos que ocorrem em um tempo próximo.

    Você misturou essas duas fontes de tempo separadas com seu código:

    NANOTIME_OFFSET = TimeUnit.SECONDS.toNanos(instant.getEpochSecond()) + instant.getNano() - nanoTime;
    

    A Instantclasse é um alvo em movimento, sendo atualizada repetidamente a qualquer momento, avançando ou retrocedendo. Portanto, sua classe NANOTIME_OFFSETé ingênua e inválida.

    • Ingênuo porque você assume uma solidez e confiabilidade no relógio de data e hora do sistema operacional host que não existe.
    • Inválido porque as duas fontes de tempo não acompanham juntas. Como nanoTimediz o Javadoc: 👉🏽 "Este método só pode ser usado para medir o tempo decorrido e não está relacionado a nenhuma outra noção de tempo de sistema ou de relógio de parede."

    Para completar, mencionarei que System.currentTimeMillis(agora legado ) foi suplantado por Instant.now. Ambos usam o relógio de data e hora do sistema operacional host. Nenhum deles deve ser misturado com System.nanoTime.


    † Hoje em dia, você pode comprar um relógio atômico por muito dinheiro (embora talvez menos do que você espera). Um tópico recente no YouTube são servidores de tempo superprecisos e muito baratos, feitos por você mesmo, baseados na captura do momento atual transmitido por navegação por satélite ( GPS , etc.) e, em seguida, servidos por computadores baratos como o Raspberry Pi. Para explorar essa toca do coelho dos gênios do tempo, você pode começar com os canais de Jeff Geerling .

    • 3

relate perguntas

  • Lock Condition.notify está lançando java.lang.IllegalMonitorStateException

  • Resposta de microsserviço Muitos para Um não aparece no carteiro

  • Validação personalizada do SpringBoot Bean

  • Os soquetes Java são FIFO?

  • Por que não é possível / desencorajado definir um lado do servidor de tempo limite de solicitação?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve