Helpex - Trao đổi & giúp đỡ Đăng nhập
149

Như tài liệu trong bài đăng trên blog Cảnh giác với System.nanoTime () trong Java , trên các hệ thống x86, System.nanoTime () của Java trả về giá trị thời gian bằng cách sử dụng bộ đếm cụ thể của CPU . Bây giờ hãy xem xét trường hợp sau đây tôi sử dụng để đo thời gian của một cuộc gọi:

long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;

Bây giờ trong một hệ thống đa lõi, có thể là sau khi đo thời gian1, luồng được lên lịch tới một bộ xử lý khác có bộ đếm nhỏ hơn CPU trước đó. Do đó, chúng ta có thể nhận được một giá trị trong time2 nhỏ hơn time1. Do đó, chúng tôi sẽ nhận được một giá trị âm trong timeSpent.

Xem xét trường hợp này, phải chăng System.nanotime bây giờ khá vô dụng?

Tôi biết rằng việc thay đổi thời gian hệ thống không ảnh hưởng đến nano. Đó không phải là vấn đề tôi mô tả ở trên. Vấn đề là mỗi CPU sẽ giữ một bộ đếm khác nhau kể từ khi nó được bật. Bộ đếm này có thể thấp hơn trên CPU thứ hai so với CPU thứ nhất. Do luồng có thể được HĐH lên lịch cho CPU thứ hai sau khi nhận time1, giá trị của timeSpent có thể không chính xác và thậm chí âm.

149 hữu ích 3 bình luận 108k xem chia sẻ
15 trả lời 15
202

Câu trả lời này được viết vào năm 2011 theo quan điểm của Sun JDK thời đó chạy trên các hệ điều hành thời đó thực sự đã làm gì. Đó là một thời gian dài trước đây! Câu trả lời của leventov cung cấp một viễn cảnh cập nhật hơn.

Bài đăng đó là sai, và nanoTimean toàn. Có một bình luận về bài đăng liên kết đến một bài đăng trên blog của David Holmes , một anh chàng thời gian thực và đồng thời tại Sun. Nó nói rằng:

System.nanoTime () được triển khai bằng API QueryPerformanceCorer / QueryPerformanceFrequency [...] Cơ chế mặc định được QPC sử dụng được xác định bởi lớp Trừu tượng phần cứng (HAL) [...] phiên bản. Ví dụ: Windows XP Service Pack 2 đã thay đổi mọi thứ để sử dụng bộ hẹn giờ quản lý năng lượng (PMTimer) thay vì bộ đếm thời gian của bộ xử lý (TSC) do các sự cố với TSC không được đồng bộ hóa trên các bộ xử lý khác nhau trong các hệ thống SMP có thể thay đổi (và do đó mối quan hệ của nó với thời gian trôi qua) dựa trên các cài đặt quản lý năng lượng.

Vì vậy, trên Windows, đây một vấn đề cho đến WinXP SP2, nhưng bây giờ thì không.

Tôi không thể tìm thấy phần II (hoặc nhiều hơn) nói về các nền tảng khác, nhưng bài viết đó bao gồm một nhận xét mà Linux đã gặp phải và giải quyết vấn đề tương tự theo cách tương tự, với liên kết đến Câu hỏi thường gặp cho clock_gettime (CLOCK_REALTIME) , mà nói:

  1. Clock_gettime (CLOCK_REALTIME) có nhất quán trên tất cả các bộ xử lý / lõi không? (Có vấn đề về vòm không? Ví dụ: ppc, arm, x86, amd64, sparc).

nên hoặc nó được coi là lỗi.

Tuy nhiên, trên x86 / x86_64, có thể thấy các TSC freq không đồng bộ hoặc biến đổi gây ra sự không nhất quán về thời gian. Hạt nhân 2,4 thực sự không có sự bảo vệ chống lại điều này, và hạt nhân 2,6 đầu cũng không làm quá tốt ở đây. Kể từ 2.6,18 trở lên logic để phát hiện điều này là tốt hơn và chúng ta thường sẽ quay trở lại với nguồn đồng hồ an toàn.

ppc luôn có một cơ sở thời gian được đồng bộ hóa, vì vậy đó không phải là một vấn đề.

Vì vậy, nếu liên kết của Holmes có thể được đọc là ngụ ý nanoTimecác cuộc gọi clock_gettime(CLOCK_REALTIME)đó, thì đó là sự an toàn của kernel 2.6.18 trên x86 và luôn luôn trên PowerPC (vì IBM và Motorola, không giống như Intel, thực sự biết cách thiết kế bộ vi xử lý).

Đáng buồn thay, không có đề cập đến SPARC hay Solaris. Và tất nhiên, chúng tôi không biết IBM JVM làm gì. Nhưng Sun JVM trên Windows và Linux hiện đại đã hiểu điều này.

EDIT: Câu trả lời này dựa trên các nguồn mà nó trích dẫn. Nhưng tôi vẫn lo lắng rằng nó thực sự có thể sai hoàn toàn. Một số thông tin cập nhật hơn sẽ thực sự có giá trị. Tôi vừa tìm thấy một liên kết đến một bài báo mới hơn bốn năm về đồng hồ của Linux có thể hữu ích.

202 hữu ích 5 bình luận chia sẻ
35

Tôi đã thực hiện một chút tìm kiếm và thấy rằng nếu một người đang phạm tội thì có thể coi đó là vô dụng ... trong các tình huống cụ thể ... nó phụ thuộc vào mức độ nhạy cảm của các yêu cầu của bạn ...

Kiểm tra trích dẫn này từ trang web Java Sun:

Đồng hồ thời gian thực và System.nanoTime () đều dựa trên cùng một cuộc gọi hệ thống và do đó cùng một đồng hồ.

Với Java RTS, tất cả các API dựa trên thời gian (ví dụ: Bộ hẹn giờ, Chủ đề định kỳ, Giám sát thời hạn, v.v.) đều dựa trên bộ định thời có độ phân giải cao. Và, cùng với các ưu tiên thời gian thực, họ có thể đảm bảo rằng mã phù hợp sẽ được thực thi vào đúng thời điểm cho các ràng buộc thời gian thực. Ngược lại, các API Java SE thông thường chỉ cung cấp một vài phương thức có khả năng xử lý thời gian có độ phân giải cao, không đảm bảo thực thi tại một thời điểm nhất định. Sử dụng System.nanoTime () giữa các điểm khác nhau trong mã để thực hiện các phép đo thời gian đã trôi qua phải luôn chính xác.

Java cũng có một cảnh báo cho phương thức nanoTime () :

Phương pháp này chỉ có thể được sử dụng để đo thời gian trôi qua và không liên quan đến bất kỳ khái niệm nào khác về thời gian của hệ thống hoặc đồng hồ treo tường. Giá trị được trả về đại diện cho nano giây do một số thời gian cố định nhưng tùy ý (có thể trong tương lai, vì vậy giá trị có thể âm). Phương pháp này cung cấp độ chính xác nano giây, nhưng không nhất thiết là độ chính xác nano giây. Không có đảm bảo nào được thực hiện về tần suất thay đổi giá trị. Sự khác biệt trong các cuộc gọi liên tiếp kéo dài hơn khoảng 292,3 năm (2 63 nano giây) sẽ không tính toán chính xác thời gian đã trôi qua do tràn số.

Dường như kết luận duy nhất có thể được rút ra là nanoTime () không thể dựa vào như một giá trị chính xác. Như vậy, nếu bạn không cần đo thời gian chỉ cách nhau nano giây thì phương pháp này đủ tốt ngay cả khi giá trị trả về kết quả là âm. Tuy nhiên, nếu bạn cần độ chính xác cao hơn, họ dường như khuyên bạn nên sử dụng JAVA RTS.

Vì vậy, để trả lời câu hỏi của bạn ... không có nanoTime () không vô dụng .... nó chỉ không phải là phương pháp khôn ngoan nhất để sử dụng trong mọi tình huống.

35 hữu ích 5 bình luận chia sẻ
18

Không cần phải tranh luận, chỉ cần sử dụng nguồn. Ở đây, SE 6 cho Linux, đưa ra kết luận của riêng bạn:

jlong os::javaTimeMillis() {
  timeval time;
  int status = gettimeofday(&time, NULL);
  assert(status != -1, "linux error");
  return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);
}


jlong os::javaTimeNanos() {
  if (Linux::supports_monotonic_clock()) {
    struct timespec tp;
    int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
    assert(status == 0, "gettime error");
    jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
    return result;
  } else {
    timeval time;
    int status = gettimeofday(&time, NULL);
    assert(status != -1, "linux error");
    jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
    return 1000 * usecs;
  }
}
18 hữu ích 1 bình luận chia sẻ
10

Tuyên bố miễn trừ trách nhiệm: Tôi là nhà phát triển của thư viện này

Bạn có thể thích điều này tốt hơn:

http://juliusdavies.ca/nanotime/

Nhưng nó sao chép tệp DLL hoặc Unix .so (đối tượng dùng chung) vào thư mục chính của người dùng hiện tại để có thể gọi JNI.

Một số thông tin cơ bản có trên trang web của tôi tại:

http://juliusdavies.ca/poseix_clocks/clock_realtime_linux_faq.html

10 hữu ích 1 bình luận chia sẻ
7

Vì Java 7, System.nanoTime()được đảm bảo an toàn bởi đặc tả JDK. System.nanoTime()Javadoc cho thấy rõ rằng tất cả các yêu cầu được quan sát trong một JVM (nghĩa là trên tất cả các luồng) là đơn điệu:

Giá trị được trả về đại diện cho nano giây do một số thời gian gốc cố định nhưng tùy ý (có thể trong tương lai, vì vậy giá trị có thể âm). Cùng một nguồn gốc được sử dụng bởi tất cả các yêu cầu của phương thức này trong một thể hiện của máy ảo Java; các trường hợp máy ảo khác có khả năng sử dụng một nguồn gốc khác.

Việc triển khai JVM / JDK chịu trách nhiệm loại bỏ những mâu thuẫn có thể quan sát được khi các tiện ích hệ điều hành cơ bản được gọi (ví dụ: những tiện ích được đề cập trong câu trả lời của Tom Anderson ).

Phần lớn các câu trả lời cũ khác cho câu hỏi này (được viết vào năm 20092012) thể hiện FUD có thể phù hợp với Java 5 hoặc Java 6 nhưng không còn phù hợp với các phiên bản Java hiện đại.

Tuy nhiên, điều đáng nói là mặc dù có nanoTime()sự an toàn của JDK , nhưng đã có một số lỗi trong OpenJDK khiến nó không duy trì được sự bảo đảm này trên các nền tảng nhất định hoặc trong một số trường hợp nhất định (ví dụ: JDK-8040140 , JDK-8184271 ). Hiện tại không có lỗi mở (đã biết) trong OpenJDK wrt nanoTime(), nhưng việc phát hiện ra một lỗi mới như vậy hoặc hồi quy trong bản phát hành mới hơn của OpenJDK không gây sốc cho bất kỳ ai.

Với ý nghĩ đó, mã sử dụng nanoTime()để chặn thời gian, chờ khoảng thời gian, hết thời gian, v.v. tốt nhất nên coi chênh lệch thời gian âm (thời gian chờ) là số không thay vì ném ngoại lệ. Thực hành này cũng là một lợi thế vì nó phù hợp với hành vi của tất cả các phương pháp chờ đợi đúng lúc trong mọi tầng lớp trong java.util.concurrent.*, ví dụ Semaphore.tryAcquire(), Lock.tryLock(), BlockingQueue.poll()vv

Tuy nhiên, nanoTime()vẫn nên được ưu tiên để thực hiện chặn thời gian, chờ khoảng thời gian, hết thời gian, v.v. currentTimeMillis()bởi vì sau này là đối tượng của hiện tượng "thời gian quay ngược" (ví dụ do điều chỉnh thời gian của máy chủ), tức currentTimeMillis()là không phù hợp để đo khoảng thời gian ở tất cả. Xem câu trả lời này để biết thêm thông tin.

Thay vì sử dụng nanoTime()cho phép đo thời gian thực hiện mã trực tiếp, khung điểm chuẩn chuyên ngành và profilers tốt nhất nên được sử dụng, ví dụ JMHasync-profiler trong chế độ profiling tường đồng hồ .

7 hữu ích 0 bình luận chia sẻ
6

Linux sửa lỗi cho sự khác biệt giữa các CPU, nhưng Windows thì không. Tôi đề nghị bạn giả sử System.nanoTime () chỉ chính xác trong khoảng 1 micro giây. Một cách đơn giản để có thời gian dài hơn là gọi foo () 1000 lần trở lên và chia thời gian cho 1000.

6 hữu ích 5 bình luận chia sẻ
5

Tuyệt đối không vô dụng. Thời gian người hâm mộ chỉ ra chính xác vấn đề đa lõi, nhưng trong các ứng dụng thực sự, nó thường tốt hơn hoàn toàn so với currentTimeMillis ().

Khi tính toán các vị trí đồ họa trong khung làm mới nanoTime () dẫn đến chuyển động mượt mà hơn trong chương trình của tôi.

Và tôi chỉ thử nghiệm trên các máy đa lõi.

5 hữu ích 0 bình luận chia sẻ
4

Tôi đã thấy thời gian trôi qua tiêu cực được báo cáo từ việc sử dụng System.nanoTime (). Để rõ ràng, mã trong câu hỏi là:

    long startNanos = System.nanoTime();

    Object returnValue = joinPoint.proceed();

    long elapsedNanos = System.nanoTime() - startNanos;

và biến 'elapsedNanos' có giá trị âm. (Tôi khẳng định rằng cuộc gọi trung gian cũng mất ít hơn 293 năm, đó là điểm tràn cho các nanos được lưu trữ trong thời gian dài :)

Điều này xảy ra khi sử dụng IBM v1.5 JRE 64bit trên phần cứng IBM P690 (đa lõi) chạy AIX. Tôi chỉ thấy lỗi này xảy ra một lần, nên có vẻ như rất hiếm. Tôi không biết nguyên nhân - đó có phải là sự cố cụ thể về phần cứng, lỗi JVM - tôi không biết. Tôi cũng không biết ý nghĩa của tính chính xác của nanoTime () nói chung.

Để trả lời câu hỏi ban đầu, tôi không nghĩ nanoTime là vô ích - nó cung cấp thời gian dưới một phần nghìn giây, nhưng có một rủi ro thực tế (không chỉ là lý thuyết) về việc nó không chính xác mà bạn cần tính đến.

4 hữu ích 2 bình luận chia sẻ
2

Đây dường như không phải là vấn đề đối với Core 2 Duo chạy Windows XP và JRE 1.5.0_06.

Trong một thử nghiệm với ba luồng tôi không thấy System.nanoTime () đi ngược lại. Các bộ xử lý đều bận rộn và thỉnh thoảng đi ngủ để kích thích các luồng di chuyển xung quanh.

[EDIT] Tôi đoán rằng điều đó chỉ xảy ra trên các bộ xử lý riêng biệt, tức là các bộ đếm được đồng bộ hóa cho nhiều lõi trên cùng một khuôn.

2 hữu ích 4 bình luận chia sẻ
2

Không, không phải ... Nó chỉ phụ thuộc vào CPU của bạn, hãy kiểm tra Bộ đếm thời gian chính xác cao để biết cách / lý do mọi thứ được xử lý khác nhau theo CPU.

Về cơ bản, hãy đọc nguồn Java của bạn và kiểm tra xem phiên bản của bạn có chức năng gì và nếu nó hoạt động dựa trên CPU, bạn sẽ chạy nó trên đó.

IBM thậm chí còn đề nghị bạn sử dụng nó để đánh giá hiệu năng (một bài đăng năm 2008, nhưng đã cập nhật).

2 hữu ích 1 bình luận chia sẻ
2

Tôi đang liên kết đến những gì về cơ bản là cùng một cuộc thảo luận nơi Peter Lawrey đang cung cấp một câu trả lời tốt. Tại sao tôi nhận được thời gian trôi qua tiêu cực khi sử dụng System.nanoTime ()?

Nhiều người đã đề cập rằng trong Java System.nanoTime () có thể trả về thời gian âm. Tôi đã xin lỗi vì đã lặp lại những gì người khác đã nói.

  1. nanoTime () không phải là đồng hồ mà là bộ đếm chu kỳ CPU.
  2. Giá trị trả về được chia theo tần số để trông giống như thời gian.
  3. Tần số CPU có thể dao động.
  4. Khi luồng của bạn được lên lịch trên CPU khác, có khả năng nhận nanoTime () dẫn đến sự khác biệt âm. Điều đó hợp lý. Bộ đếm trên CPU không được đồng bộ hóa.
  5. Trong nhiều trường hợp, bạn có thể nhận được kết quả khá sai lệch nhưng bạn sẽ không thể biết vì delta không âm. Hãy suy nghĩ về nó.
  6. (chưa được xác nhận) Tôi nghĩ rằng bạn có thể nhận được kết quả âm ngay cả trên cùng một CPU nếu các hướng dẫn được sắp xếp lại. Để ngăn chặn điều đó, bạn phải gọi một rào cản bộ nhớ nối tiếp các hướng dẫn của bạn.

Sẽ thật tuyệt nếu System.nanoTime () trả về coreID nơi nó được thực thi.

2 hữu ích 5 bình luận chia sẻ
1

Java là nền tảng chéo và nanoTime phụ thuộc vào nền tảng. Nếu bạn sử dụng Java - khi không sử dụng nanoTime. Tôi tìm thấy các lỗi thực sự trên các triển khai jvm khác nhau với chức năng này.

1 hữu ích 0 bình luận chia sẻ
0

Tài liệu Java 5 cũng khuyến nghị sử dụng phương thức này cho cùng mục đích.

Phương pháp này chỉ có thể được sử dụng để đo thời gian trôi qua và không liên quan đến bất kỳ khái niệm nào khác về thời gian của hệ thống hoặc đồng hồ treo tường.

Tài liệu API Java 5

0 hữu ích 0 bình luận chia sẻ
0

Ngoài ra, System.currentTimeMillies()thay đổi khi bạn thay đổi đồng hồ hệ thống, trong khi System.nanoTime()không, vì vậy, cái sau sẽ an toàn hơn để đo thời lượng.

0 hữu ích 0 bình luận chia sẻ
3

nanoTimelà cực kỳ không an toàn cho thời gian. Tôi đã thử nó trên các thuật toán kiểm tra tính nguyên thủy cơ bản của mình và nó đã đưa ra các câu trả lời cách nhau đúng một giây cho cùng một đầu vào. Đừng sử dụng phương pháp lố bịch đó. Tôi cần một cái gì đó chính xác và chính xác hơn là có được mili thời gian, nhưng không tệ như nanoTime.

3 hữu ích 1 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ java nanotime , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading