Rumah  >  Artikel  >  Mengapakah masa berlalu dikira dalam tetingkap masa yang besar berbeza sehingga 100+ milisaat antara System.currentTimeMillis dan System.nanoTime

Mengapakah masa berlalu dikira dalam tetingkap masa yang besar berbeza sehingga 100+ milisaat antara System.currentTimeMillis dan System.nanoTime

王林
王林ke hadapan
2024-02-09 10:24:08870semak imbas

Editor PHP Apple akan menerangkan sebab masa berlalu yang dikira pada tetingkap masa yang besar mempunyai perbezaan sehingga 100+ milisaat antara System.currentTimeMillis dan System.nanoTime. Isu ini melibatkan mekanisme asas sistem komputer dan kaedah penjadualan sistem pengendalian. Apabila mengira masa berlalu, System.currentTimeMillis menggunakan masa jam dinding yang disediakan oleh sistem pengendalian, manakala System.nanoTime menggunakan kitaran jam CPU. Disebabkan oleh mekanisme penjadualan sistem pengendalian dan sifat tak segerak jam perkakasan, kedua-dua kaedah pemasaan ini akan menyebabkan perbezaan masa. Sebab dan penyelesaian khusus akan diperkenalkan secara terperinci dalam artikel berikut. kandungan soalan dikira sebagai bilangan mikrosaat berlalu sejak kali pertama seketika, dan nilai bermula pada kali kedua seketika. Gunakan masa berlalu yang dikira daripada masa nano dan tambahkannya pada milisaat segera awal supaya kita boleh mengira zaman dengan ketepatan mikrosaat pada bila-bila masa selepas jvm bermula (semuanya dalam jvm yang sama).

//Pengumpulan statik masa nano awal dan millis semasa

//Mulai dari sini, apabila masa semasa dengan ketepatan mikro/nanosaat diperlukan, hitung masa berlalu daripada masa nano dan tambah milisaat berlalu kepada initialmillis, dan masa berlalu selebihnya memberikan masa dengan ketepatan mikrosaat

最终长 inittimenanos = system.nanotime();最终长 inittimemillis = system.currenttimemillis();

//Monotoni meningkatkan cap waktu milisaat sejak jvm bermula (zaman, kami mungkin tidak memanggilnya zaman)

//Ketepatan masa tambahan daripada nanotimefinal long elapsednanotime = system.nanotime() - inittimenanos;最终双精度 elapsedmillisfromnanotime = elapsednanos / (1000000.0);

Pertimbangkan untuk menggunakan nilai ini untuk menjana ksuid yang meningkat secara monoton yang menghampiri masa semasa tetapi dijamin untuk diisih berdasarkan masa penciptaan dalam jvm yang sama, memandangkan currenttimemillis tidak memberikan jaminan cap waktu yang meningkat secara monoton, pertimbangkan untuk menggunakan pendekatan ini untuk menjana kira-kira cap masa yang meningkat secara monoton bagi cap masa sebenar (mungkin berbeza-beza beberapa milisaat melainkan pelarasan detik lompat dibuat pada masa zaman). Masa berlalu yang dikira menggunakan zaman dan masa nano dijangka berbeza dengan beberapa milisaat, tetapi perbezaan sebenar sangat kerap berubah, dan apabila saya menjalankan ujian di bawah selama 48 jam, saya melihat perbezaan sehingga 150 milisaat antara kedua-duanya. Dalam kebanyakan kes, masa berlalu yang dikira menggunakan masa nano adalah lebih tinggi daripada masa berlalu yang dikira menggunakan currenttimemillis, dan masa yang diperhatikan berjulat dari -2 milisaat hingga +150 milisaat.

final 长计算当前时间millis = inittimemillis + elapsedmillisfromnanotime; final long nanosprecision = elapsednanos % 1000000;

//Millisaat masa berlalu daripada system.currenttimemillis()

//Perbezaan masa berlalu

Adakah saya terlepas apa-apa tentang jaminan pemasaan jvm, adakah cara pengiraan cap masa anggaran meningkat secara monoton salah? (Ini tidak digunakan sebagai zaman sebenar dalam sistem, hanya untuk menjana uuid yang juga mewakili anggaran cap waktu segera dalam jvm yang sama). final long elapsedmillis = system.currenttimemillis() - inittimemillis; 最终双方差millis = elapsedmillisfromnanotime - elapsedmillis; // Kelas ujian

package org.example;

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws Exception {
        final long initTimeNanos = System.nanoTime();
        final long initTimeMillis = System.currentTimeMillis();
        System.out.println("Nanos: " + initTimeNanos);
        System.out.println("Millis: " + initTimeMillis);

        while (true) {
            final long currentNanos = System.nanoTime();
            final long elapsedNanos = currentNanos - initTimeNanos;
            final double elapsedMillisFromNanos = elapsedNanos / 1000000.0;
            final long elapsedMillis = System.currentTimeMillis() - initTimeMillis;
            final double varianceMillis = elapsedMillisFromNanos - elapsedMillis;
            if (Math.abs(varianceMillis) > 1) {
                System.out.printf("\nVariance Observed: %.6f\n", varianceMillis);
                System.out.printf("Elapsed Time: %.6fms (from System.nanoTime)\n", elapsedMillisFromNanos);
                System.out.printf("Elapsed Time: %dms (from System.currentTimeMillis)\n", elapsedMillis);
            }
            if (elapsedMillis > TimeUnit.HOURS.toMillis(48)) {
                break;
            }
            Thread.sleep(5000);
            System.out.print(".");
        }
    }
}

Mengapa varians masa berlalu terus berubah? Apakah varians maksimum yang boleh kita jangkakan jika jvm berjalan secara berterusan selama setahun (mana-mana jvm menjamin sempadan atas atau bawah pada ini, diuji dengan mac dan windows, mac memberikan peningkatan yang perlahan dalam varians, tingkap adalah lebih cepat) ?

Saya menjangkakan masa berlalu berubah kurang daripada 10 milisaat dan perubahan berlaku kurang kerap. Tetapi pemerhatian sebenar adalah bahawa varians terus berubah, turun naik naik dan turun, dengan sehingga 150 milisaat diperhatikan dalam masa 48 jam

Penyelesaian

Satu penjelasan ialah calitan masa berdasarkan ntp. Secara umumnya, masa nano dan ctm mengukur perkara yang sama sekali berbeza dan anda tidak boleh mencampurkannya.

nanotime mempunyai 0 mata sewenang-wenangnya (mendapat nanotime 0 tidak mempunyai makna yang istimewa), jadi tidak perlu memanggilnya sama sekali selain membandingkan apa yang ia kembalikan dengan hasil panggilan nanotime yang berbeza. trek masa nano masa berlalu, itu sahaja.

system.ctm mendapat jam sistem. Jika anda menggunakan posix

apa yang dikembalikan. ctm juga secara amnya jauh lebih perlahan daripada masa nano. ctm juga mempunyai 0 yang jelas - mewakili UTC tengah malam 1 Januari 1970.

Soalan: "Saya mahu masa semasa sepadan dengan jam sistem dengan ketepatan nanosaat" adalah

tidak mungkindate 命令或在系统设置中编辑系统的时间设置,则不会影响 nanotime,但会更改 system.ctm pada jvm.

时间涂抹是指某些网络时间守护程序注意到您的系统时钟略有偏差,并且不只是将系统时钟编辑到正确的时间,而是引入了涂抹:假设您比实时时间“提前”了 400 毫秒。 ntp 可以将您的时钟向后设置 400 毫秒,但许多日志记录系统假设 system.ctm 不会向后移动(这是一个不正确但广泛应用的假设)。

这可以通过让时间放慢一段时间来“修复”:每经过 100 毫秒,ntp 守护进程就会将时钟“保持”在同一毫秒上一毫秒。每 100 毫秒就赶上 1 毫秒,因此在 400,000 毫秒(仅 400 秒)内,时钟恢复与网络同步,并且日志记录根本不受影响。

但是,这显然会完全破坏 system.ctm 和 nanotime 之间的任何关系!

大多数 ntp 都是这样涂抹的(它们也会向前涂抹 - 如果您的系统时钟落后,它不仅仅会向前跳跃:这会使日志撒谎(使其看起来就像两个事件之间存在一些间隙)比实际大得多),因此每 100 毫秒,ntp 就会使时钟跳过一毫秒,类似这样的事情,以赶上。

...但我需要单调递增的时间戳!

那么 nanotime 就无关紧要了。不要使用它。

拥有一些提供 id 的集中“商店”。一种实现:

class TimeStore {
  long lastVal = 0L;

  public synchronized long get() {
    long mark = System.currentTimeMillis() << 4;
    return lastVal = Math.max(mark, lastVal + 1);
  }
}

这将返回当前时间,左移 4 位,并将填充此移位“释放”的 16 个值,以便能够在同一时间生成单调递增值,最多 16 次;同一毫秒内的任何进一步请求都会潜入下一毫秒。

尽管如此,这可能并不比nanotime慢。

rzwitserloot的回答是正确的。我将向您提供我对各种问题的看法。

currenttimemillisnanotime 无关

system.currenttimemillissystem.nanotime 彼此无关。

  • currenttimemillis 从主机的硬件时钟单元检索当前日期和时间,由主机操作系统管理。
  • nanotime 来自主机 cpu 保存的计数。

currenttimemillis

所以首先要了解人类的年月日和时分秒的概念。传统计算机中使用的时钟硬件的分辨率有限,有些是毫秒,有些是微秒,但没有纳秒。

由于各种原因,本次通话报告的日期和时间可能会有所不同。其中一个原因是,在电池电量耗尽的情况下启动的计算机会将其时钟重置为默认时刻,直到通过调用时间服务器进行纠正。另一个原因是系统管理员或用户可能会更改日期时间。还有一个原因是硬件时钟可能无法很好地保持时间,并且会通过调用时间服务器在更新之间运行得快或慢。

nanotime

nanotime 调用以纳秒计数形式告知经过的时间。但这个流逝的时间与日历和墙上的时钟无关。此调用仅返回经过的纳秒的单调计数。

这个计数非常准确,因为它来自计算机的“跳动的心脏”。返回的数量始终在增加,直到达到 long.max_value,然后环绕到 long.min_value。这给出了大约 292 年的范围,但这并不意味着从现在起 292 年。计数的起点未指定。在某些 java 实现中,您可能会看到计数在计算机启动时开始。但并不能保证这一点。

问题

您可能会考虑寻找 新 6、7、8 版本 的实现a href="https://en.wikipedia.org/wiki/universally_unique_identifier" rel="nofollow noreferrer">uuid 被提议给 ietf 进行标准化。

currenttimemillis 在现代 java 中已被 java.time.instant 类取代。调用 instant.now 捕获 utc 中的当前时刻。

java 9+ 中的常见实现以微秒为单位报告,但在 java 8 中以毫秒为单位。 instant 类能够以纳秒为单位。

Idea bijak. Tetapi ia tidak realistik. Seperti yang dinyatakan di atas, currenttimemillisnanotime 不相关。最重要的是,currenttimemillis 的结果可能会因多种原因而有所不同。同时,nanotime 计数可能会随着主机的每次启动而变化,并且肯定不会对应于其他计算机上进行的任何 nanotime panggilan.

Ya, anda mengabaikan fakta bahawa spesifikasi java tidak membuat sebarang jaminan yang anda seolah-olah andaikan.

Satu-satunya jaminan dalam

javadoc ialah nanotime 是“高分辨率”,至少与 currenttimemillis adalah sama baiknya. Dan tiada jaminan apabila anda boleh menjangkakan penghujung 292.

Pada masa yang sama, currenttimemillis ialah sasaran yang bergerak dan boleh berubah pada bila-bila masa, bergerak ke hadapan atau ke belakang.

Ia tidak dapat diramalkan.

Spesifikasi Java tidak memberikan jaminan sedemikian.

Atas ialah kandungan terperinci Mengapakah masa berlalu dikira dalam tetingkap masa yang besar berbeza sehingga 100+ milisaat antara System.currentTimeMillis dan System.nanoTime. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam