ฉันจะจับเวลาการเรียกใช้เมธอดใน Java ได้อย่างไร


834
  1. ฉันจะรับเวลาดำเนินการของวิธีได้อย่างไร
  2. มีTimerคลาสยูทิลิตี้สำหรับสิ่งต่าง ๆ เช่นเวลาที่ต้องใช้เวลานานหรือไม่?

การค้นหาส่วนใหญ่ใน Google ส่งคืนผลลัพธ์สำหรับตัวจับเวลาที่กำหนดหัวข้อและงานซึ่งไม่ใช่สิ่งที่ฉันต้องการ


JAMon API เป็นฟรี Java API ที่ปลอดภัยง่ายและมีประสิทธิภาพสูงซึ่งช่วยให้นักพัฒนาสามารถตรวจสอบประสิทธิภาพและความยืดหยุ่นของแอปพลิเคชันการผลิต JAMon ติดตามจำนวนการเข้าชมเวลาดำเนินการ (รวม, เฉลี่ย, min, max, std dev) และอื่น ๆ http://jamonapi.sourceforge.net/ดาวน์โหลด: http://sourceforge.net/project/showfiles.php?group_id=96550
— Mike Pone

1
คุณอาจต้องการดูคลาสApache Commons Lang StopWatch คลาสยูทิลิตี้ที่เรียบง่าย แต่มีประโยชน์


ใช่ StopWatch เหมาะสำหรับสิ่งนี้
— Shubham Pandey

Java 8 ใช้Instantคลาส: stackoverflow.com/a/30975902/1216775
— akhil_mittal

คำตอบ:


1207

มีวิธีที่ล้าสมัยอยู่เสมอ:

long startTime = System.nanoTime();
methodToTime();
long endTime = System.nanoTime();

long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.

233
ที่จริงแล้วมันเป็น "new-fashioned" เพราะคุณใช้ nanoTime ซึ่งไม่ได้เพิ่มจนกระทั่ง java5
— John Gardner

11
(หรือการใช้ System.currentTimeMillis ()) นี้ดูเหมือนจะเป็นวิธีที่มักจะทำใน Java ... ที่ฉันเคยเห็นแล้ว มันยังทำให้ฉันประหลาดใจเล็กน้อยว่าไม่มีคลาสบิวท์อินที่สวยงามเช่น Timer t = new Timer (); String s = t.getElapsed (รูปแบบ); ฯลฯ ...
— Ogre Psalm33

18
nanoTime ไม่รับประกันความถูกต้องดีกว่า currentTimeMillis () ถึงแม้ว่ามันมักจะทำก็ตาม forums.sun.com/thread.jspa?messageID=9460663และsimongbrown.com/blog/2007/08/20//
— James

10
แน่นอนว่าเป็นเรื่องสำคัญที่จะต้องจำข้อผิดพลาดของการวัดขนาดเล็กเช่นการเพิ่มประสิทธิภาพของคอมไพเลอร์ / JVM ที่อาจบิดเบือนผลลัพธ์ = 8-)
— Yuval

18
ไม่จำเป็นต้องมีการบล็อกในที่สุดเนื่องจากจะไม่ใช้ endTime หากมีข้อผิดพลาดเกิดขึ้น
— Peter Lawrey

197

ฉันไปกับคำตอบง่ายๆ ได้ผลสำหรับฉัน

long startTime = System.currentTimeMillis();

doReallyLongThing();

long endTime = System.currentTimeMillis();

System.out.println("That took " + (endTime - startTime) + " milliseconds");

มันใช้งานได้ค่อนข้างดี ความละเอียดชัดเป็นเพียงมิลลิวินาทีเท่านั้นคุณสามารถทำได้ดีกว่าด้วย System.nanoTime () มีข้อ จำกัด บางอย่างสำหรับทั้งสอง (ตัวแบ่งกำหนดการของระบบปฏิบัติการ ฯลฯ ) แต่วิธีนี้ใช้ได้ค่อนข้างดี

ค่าเฉลี่ยในการวิ่งสองรอบ (ยิ่งดี) และคุณจะได้รับความคิดที่ดี


51
ที่จริงแล้ว System.currentTimeMillis () นั้นมีความแม่นยำสูงกว่า 15ms เท่านั้น สำหรับค่าต่ำจริง ๆ ไม่สามารถเชื่อถือได้ วิธีแก้ปัญหาสำหรับเรื่องนี้ (ดังที่กล่าวไว้) คือ System.nanoTime ();
— Steve g

ตกลงฉันกำลังจะยอมรับสิ่งนี้เป็นคำตอบอย่างเป็นทางการจนกว่าฉันจะอ่านความคิดเห็นของสตีฟจี อาหารอันโอชะที่ดีสตีฟ!
— Ogre Psalm33

4
nanoTime () ไม่รับประกันความถูกต้องดีกว่า currentTimeMillis แต่การใช้ JVM จำนวนมากมีความแม่นยำที่ดีขึ้นเมื่อใช้ nanoTime
— James Schek

5
@JamesSchek คุณต้องดูถ้อยคำของคุณจริงๆเพราะฉันได้พูดถึงความคิดเห็นที่เหมือนกันนี้แล้วที่อื่น; nanoTimeรับประกันได้ว่าจะอย่างน้อยเป็นอย่างเด็ดเดี่ยวcurrentTimeMillisเป็น docs.oracle.com/javase/7/docs/api/java/lang/…
— b1nary.atr0phy

ข้อได้เปรียบเล็กน้อยอย่างหนึ่งcurrentTimeMillisคือมันเป็นเวลาที่แท้จริงและสามารถใช้ในการบันทึกเวลาเริ่มต้น / สิ้นสุดได้เช่นกันในขณะที่nanoTime"สามารถใช้เพื่อวัดเวลาที่ผ่านไปและไม่เกี่ยวข้องกับความคิดอื่น ๆ ของระบบหรือเวลานาฬิกา ."
— Brad Parks

177

มากับพวก! ไม่มีใครพูดถึงวิธีการทำฝรั่ง (ซึ่งน่ากลัวมาก):

import com.google.common.base.Stopwatch;

Stopwatch timer = Stopwatch.createStarted();
//method invocation
LOG.info("Method took: " + timer.stop());

สิ่งที่ดีคือ Stopwatch.toString () ทำงานได้ดีในการเลือกหน่วยเวลาสำหรับการวัด นั่นคือถ้าค่ามีขนาดเล็กมันจะออกมา 38 ns ถ้ามันยาวมันจะแสดง 5m 3s

ยิ่งดีกว่า:

Stopwatch timer = Stopwatch.createUnstarted();
for (...) {
   timer.start();
   methodToTrackTimeFor();
   timer.stop();
   methodNotToTrackTimeFor();
}
LOG.info("Method took: " + timer);

หมายเหตุ: Google Guava ต้องการ Java 1.6+


21
น่าเสียดายที่นาฬิกาจับเวลาของ Guava ไม่ปลอดภัยสำหรับเธรด ฉันเรียนรู้วิธีนี้ยาก
— Dexter Legaspi

6
@DexterLegaspi จะสนใจประสบการณ์ของคุณมาก! สนใจที่จะแบ่งปัน?
— Siddhartha

1
การใช้นาฬิกาจับเวลาแบบขนานจะทำให้คุณโทรติดต่อกันstart()หลายครั้ง (เหมือนกันstop())
— Mingwei ซามูเอล

141

ใช้InstantและDurationจาก API ใหม่ของ Java 8

Instant start = Instant.now();
Thread.sleep(5000);
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

เอาท์พุท

PT5S

2
ขอบคุณฉันจะส่งออกผลลัพธ์โดยไม่ต้องมี PT อยู่ข้างหน้าได้อย่างไร
— java123999

1
ปัญหาเกี่ยวกับวิธีการคือ Instant นั้นไม่ได้มีปัญหาความแม่นยำที่สองเป็นพันและนาโน Ref: stackoverflow.com/questions/20689055/…
— prashantsunkari

8
@ java123999: คุณสามารถโทรDuration.between(start, end).getSeconds()ได้ Durationยังมีวิธีการแปลงเป็นหน่วยเวลาอื่น ๆ เช่นtoMillis()ซึ่งแปลงเป็นมิลลิวินาที
— Emil Lunde

100

รวบรวมวิธีที่เป็นไปได้ทั้งหมดไว้ด้วยกันในที่เดียว

วันที่

Date startDate = Calendar.getInstance().getTime();
long d_StartTime = new Date().getTime();
Thread.sleep(1000 * 4);
Date endDate = Calendar.getInstance().getTime();
long d_endTime = new Date().getTime();
System.out.format("StartDate : %s, EndDate : %s \n", startDate, endDate);
System.out.format("Milli = %s, ( D_Start : %s, D_End : %s ) \n", (d_endTime - d_StartTime),d_StartTime, d_endTime);

ระบบ. currentTimeMillis ()

long startTime = System.currentTimeMillis();
Thread.sleep(1000 * 4);
long endTime = System.currentTimeMillis();
long duration = (endTime - startTime);  
System.out.format("Milli = %s, ( S_Start : %s, S_End : %s ) \n", duration, startTime, endTime );
System.out.println("Human-Readable format : "+millisToShortDHMS( duration ) );

รูปแบบที่มนุษย์อ่านได้

public static String millisToShortDHMS(long duration) {
    String res = "";    // java.util.concurrent.TimeUnit;
    long days       = TimeUnit.MILLISECONDS.toDays(duration);
    long hours      = TimeUnit.MILLISECONDS.toHours(duration) -
                      TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes    = TimeUnit.MILLISECONDS.toMinutes(duration) -
                      TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds    = TimeUnit.MILLISECONDS.toSeconds(duration) -
                      TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    long millis     = TimeUnit.MILLISECONDS.toMillis(duration) - 
                      TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration));

    if (days == 0)      res = String.format("%02d:%02d:%02d.%04d", hours, minutes, seconds, millis);
    else                res = String.format("%dd %02d:%02d:%02d.%04d", days, hours, minutes, seconds, millis);
    return res;
}

Guava: Google Stopwatch JAR «วัตถุของนาฬิกาจับเวลาคือการวัดเวลาที่ผ่านไปในหน่วยนาโนวินาที

com.google.common.base.Stopwatch g_SW = Stopwatch.createUnstarted();
g_SW.start();
Thread.sleep(1000 * 4);
g_SW.stop();
System.out.println("Google StopWatch  : "+g_SW);

Apache Commons Lang JAR « StopWatchให้ API ที่สะดวกสำหรับการกำหนดเวลา

org.apache.commons.lang3.time.StopWatch sw = new StopWatch();
sw.start();     
Thread.sleep(1000 * 4);     
sw.stop();
System.out.println("Apache StopWatch  : "+ millisToShortDHMS(sw.getTime()) );

JODA -เวลา

public static void jodaTime() throws InterruptedException, ParseException{
    java.text.SimpleDateFormat ms_SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
    String start = ms_SDF.format( new Date() ); // java.util.Date

    Thread.sleep(10000);

    String end = ms_SDF.format( new Date() );       
    System.out.println("Start:"+start+"\t Stop:"+end);

    Date date_1 = ms_SDF.parse(start);
    Date date_2 = ms_SDF.parse(end);        
    Interval interval = new org.joda.time.Interval( date_1.getTime(), date_2.getTime() );
    Period period = interval.toPeriod(); //org.joda.time.Period

    System.out.format("%dY/%dM/%dD, %02d:%02d:%02d.%04d \n", 
        period.getYears(), period.getMonths(), period.getDays(),
        period.getHours(), period.getMinutes(), period.getSeconds(), period.getMillis());
}

Java date time API จาก Java 8 « วัตถุระยะเวลาแสดงช่วงเวลาระหว่างวัตถุทันทีสองรายการ

Instant start = java.time.Instant.now();
    Thread.sleep(1000);
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.println( between ); // PT1.001S
System.out.format("%dD, %02d:%02d:%02d.%04d \n", between.toDays(),
        between.toHours(), between.toMinutes(), between.getSeconds(), between.toMillis()); // 0D, 00:00:01.1001 

Spring Frameworkจัดเตรียมคลาสยูทิลิตี้ StopWatchเพื่อวัดเวลาที่ผ่านไปใน Java

StopWatch sw = new org.springframework.util.StopWatch();
sw.start("Method-1"); // Start a named task
    Thread.sleep(500);
sw.stop();

sw.start("Method-2");
    Thread.sleep(300);
sw.stop();

sw.start("Method-3");
    Thread.sleep(200);
sw.stop();

System.out.println("Total time in milliseconds for all tasks :\n"+sw.getTotalTimeMillis());
System.out.println("Table describing all tasks performed :\n"+sw.prettyPrint());

System.out.format("Time taken by the last task : [%s]:[%d]", 
        sw.getLastTaskName(),sw.getLastTaskTimeMillis());

System.out.println("\n Array of the data for tasks performed « Task Name: Time Taken");
TaskInfo[] listofTasks = sw.getTaskInfo();
for (TaskInfo task : listofTasks) {
    System.out.format("[%s]:[%d]\n", 
            task.getTaskName(), task.getTimeMillis());
}

เอาท์พุท:

Total time in milliseconds for all tasks :
999
Table describing all tasks performed :
StopWatch '': running time (millis) = 999
-----------------------------------------
ms     %     Task name
-----------------------------------------
00500  050%  Method-1
00299  030%  Method-2
00200  020%  Method-3

Time taken by the last task : [Method-3]:[200]
 Array of the data for tasks performed « Task Name: Time Taken
[Method-1]:[500]
[Method-2]:[299]
[Method-3]:[200]

นาฬิกาจับเวลาของ Guava, Apache Commons และ Spring Framework ไม่ปลอดภัยสำหรับเธรด ไม่ปลอดภัยสำหรับการใช้งานจริง
— Deepak Puthraya

@DeepakPuthraya ห้องสมุดใดที่จะใช้ซึ่งปลอดภัยสำหรับการใช้งานจริงหรือไม่
— gaurav

1
@DeepakPuthraya คุณสามารถใช้ Java 8 ที่ให้ Java วันเวลา API ซึ่งง่าย
— Yash

IMO โพสต์นี้จะได้รับประโยชน์หากทุกโซลูชันจะแสดงผลลัพธ์ของระบบด้วย
— BAERUS

87

ใช้ profiler (JProfiler, Netbeans Profiler, Visual VM, Eclipse Profiler ฯลฯ ) คุณจะได้ผลลัพธ์ที่ถูกต้องที่สุดและเป็นสิ่งที่รบกวนน้อยที่สุด พวกเขาใช้กลไก JVM ในตัวสำหรับการทำโปรไฟล์ซึ่งสามารถให้ข้อมูลเพิ่มเติมเช่นการติดตามสแต็กพา ธ การเรียกใช้งานและผลลัพธ์ที่ครอบคลุมมากขึ้นหากจำเป็น

เมื่อใช้ profiler แบบครบวงจรมันเป็นเรื่องเล็กน้อยที่จะสร้างโปรไฟล์วิธี คลิกขวา Profiler -> เพิ่มไปยังวิธีการรูท จากนั้นเรียกใช้ตัวสร้างโปรไฟล์เช่นเดียวกับที่คุณทำการทดสอบหรือดีบักเกอร์


นี่เป็นคำแนะนำที่ยอดเยี่ยมและหนึ่งในนั้นคือ "duh" ช่วงเวลาแสงไฟสำหรับฉันเมื่อฉันอ่านคำตอบนี้ โครงการของเราใช้ JDeveloper แต่ฉันตรวจสอบแล้วและแน่นอนว่ามันมี profiler ในตัว!
— Ogre Psalm33

2
จาก java 7 build 40 (ฉันคิดว่า) พวกเขาได้รวม JRockits Flight Recorder ตัวเก่ามาเป็นจาวา (ค้นหา Java Mission Control)
— Niels Bech Nielsen


วิธีการรับการดำเนินการวิธีการใน Java โดย Visual VM เช่น?
— okwap

41

นี่อาจไม่ใช่สิ่งที่คุณต้องการให้ฉันพูด แต่นี่เป็นการใช้ AOP ได้ดี ชัก interceptor พร็อกซี่รอบวิธีการของคุณและทำเวลาในการมี

อะไรคือสาเหตุและวิธีการของ AOP นั้นค่อนข้างจะเกินขอบเขตของคำตอบนี้น่าเศร้า แต่นั่นก็เป็นสิ่งที่ฉันควรทำ

แก้ไข: นี่คือลิงค์ไปสู่ ​​Spring AOP เพื่อให้คุณเริ่มต้นถ้าคุณกระตือรือร้น นี่เป็นการใช้งาน AOP ที่เข้าถึงได้ง่ายที่สุดสำหรับ Iive

นอกจากนี้เมื่อพิจารณาจากคำแนะนำง่ายๆของคนอื่นฉันควรเพิ่มว่า AOP ใช้เมื่อคุณไม่ต้องการให้เวลาบุกรุกรหัสของคุณ แต่ในหลาย ๆ กรณีวิธีการที่ง่ายและสะดวกนั้นก็ใช้ได้


3
นี่คือการสอนเกี่ยวกับวิธีการทำเช่นนี้กับ Spring: veerasundar.com/blog/2010/01/…
— David Tinker

39

System.currentTimeMillis();ไม่ใช่วิธีที่ดีในการวัดประสิทธิภาพของอัลกอริทึมของคุณ มันวัดเวลารวมที่คุณพบในฐานะผู้ใช้ที่ดูหน้าจอคอมพิวเตอร์ ซึ่งรวมถึงเวลาที่ทุกสิ่งทุกอย่างทำงานบนคอมพิวเตอร์ของคุณซึ่งทำงานอยู่เบื้องหลัง สิ่งนี้อาจสร้างความแตกต่างอย่างมากในกรณีที่คุณมีโปรแกรมมากมายที่ทำงานอยู่บนเวิร์กสเตชันของคุณ

วิธีการที่เหมาะสมคือใช้java.lang.managementแพ็คเกจ

จากhttp://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarkingเว็บไซต์:

  • "เวลาของผู้ใช้" คือเวลาที่ใช้เรียกใช้รหัสของแอปพลิเคชันของคุณ
  • "เวลาของระบบ" คือเวลาที่ใช้ในการเรียกใช้รหัส OS ในนามของแอปพลิเคชันของคุณ (เช่นสำหรับ I / O)

getCpuTime() วิธีการให้ผลรวมของเหล่านั้น:

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

public class CPUUtils {

    /** Get CPU time in nanoseconds. */
    public static long getCpuTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadCpuTime( ) : 0L;
    }

    /** Get user time in nanoseconds. */
    public static long getUserTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadUserTime( ) : 0L;
    }

    /** Get system time in nanoseconds. */
    public static long getSystemTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            (bean.getCurrentThreadCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L;
    }

}

4
นี่เป็นจุดที่ดีอย่างแน่นอนว่า "เวลาผู้ใช้" (เวลานาฬิกาแขวน) ไม่ได้เป็นเครื่องวัดประสิทธิภาพที่ดีเสมอไปโดยเฉพาะอย่างยิ่งในโปรแกรมแบบมัลติเธรด
— Ogre Psalm33

นี่คือคำตอบที่ฉันกำลังมองหา
— ZhaoGang

30

ด้วย Java 8 คุณสามารถทำสิ่งนี้ได้ทุกวิธีปกติ:

Object returnValue = TimeIt.printTime(() -> methodeWithReturnValue());
//do stuff with your returnValue

ด้วย TimeIt เช่น:

public class TimeIt {

public static <T> T printTime(Callable<T> task) {
    T call = null;
    try {
        long startTime = System.currentTimeMillis();
        call = task.call();
        System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s");
    } catch (Exception e) {
        //...
    }
    return call;
}
}

ด้วย methode นี้คุณสามารถทำการวัดเวลาได้อย่างง่ายดายทุกที่ในรหัสของคุณโดยไม่ทำให้มันแตก ในตัวอย่างง่ายๆนี้ฉันเพิ่งพิมพ์เวลา ขอให้คุณเพิ่มสวิตช์สำหรับ TimeIt เช่นเพื่อพิมพ์เฉพาะเวลาใน DebugMode หรือบางอย่าง

หากคุณกำลังทำงานกับฟังก์ชั่นคุณสามารถทำบางสิ่งเช่นนี้:

Function<Integer, Integer> yourFunction= (n) -> {
        return IntStream.range(0, n).reduce(0, (a, b) -> a + b);
    };

Integer returnValue = TimeIt.printTime2(yourFunction).apply(10000);
//do stuff with your returnValue

public static <T, R> Function<T, R> printTime2(Function<T, R> task) {
    return (t) -> {
        long startTime = System.currentTimeMillis();
        R apply = task.apply(t);
        System.out.print((System.currentTimeMillis() - startTime) / 1000d
                + "s");
        return apply;
    };
}

มันดูดีกว่าโซลูชันอื่น ๆ มันใกล้กับสปริง AOP แต่ก็เบากว่านั้น True java 8 way! +1 ขอบคุณ!
— Amit Kumar

บางทีนี่อาจจะดูดีสำหรับคุณเพราะ Stefan ใช้ฟังก์ชั่นจาวาแฟนซีแนวใหม่ แต่ฉันคิดว่ามันยากที่จะอ่านและเข้าใจยาก
— Stimpson Cat

18

นอกจากนี้เรายังสามารถใช้คลาส StopWatch ของ Apache สามัญเพื่อวัดเวลา

โค้ดตัวอย่าง

org.apache.commons.lang.time.StopWatch sw = new org.apache.commons.lang.time.StopWatch();

System.out.println("getEventFilterTreeData :: Start Time : " + sw.getTime());
sw.start();

// Method execution code

sw.stop();
System.out.println("getEventFilterTreeData :: End Time : " + sw.getTime());

15

เพียงแค่บิดเล็กน้อยหากคุณไม่ได้ใช้เครื่องมือและต้องการใช้วิธีการเวลาที่มีเวลาดำเนินการต่ำ: ดำเนินการหลายครั้งในแต่ละครั้งที่เพิ่มจำนวนเป็นสองเท่าของเวลาที่จะดำเนินการจนกว่าคุณจะถึงหนึ่งวินาทีหรือมากกว่านั้น ดังนั้นเวลาของการเรียกไปที่ System.nanoTime และอื่น ๆ หรือความแม่นยำของ System.nanoTime จะส่งผลต่อผลลัพธ์มากน้อยเพียงใด

    int runs = 0, runsPerRound = 10;
    long begin = System.nanoTime(), end;
    do {
        for (int i=0; i<runsPerRound; ++i) timedMethod();
        end = System.nanoTime();
        runs += runsPerRound;
        runsPerRound *= 2;
    } while (runs < Integer.MAX_VALUE / 2 && 1000000000L > end - begin);
    System.out.println("Time for timedMethod() is " + 
        0.000000001 * (end-begin) / runs + " seconds");

แน่นอนว่าคำเตือนเกี่ยวกับการใช้นาฬิกาแขวนมีผลกับการรวบรวม JIT, หลายเธรด / กระบวนการ ฯลฯ ดังนั้นคุณต้องดำเนินการวิธีการก่อนหลายครั้งก่อนเช่นคอมไพเลอร์ JIT ทำงานและจากนั้น ทำซ้ำการทดสอบนี้หลายครั้งและใช้เวลาดำเนินการต่ำที่สุด


13

เรากำลังใช้คำอธิบายประกอบ AspectJ และ Java เพื่อจุดประสงค์นี้ หากเราต้องการทราบเวลาในการดำเนินการของเมธอดเราจะอธิบายให้ง่าย เวอร์ชันขั้นสูงสามารถใช้ระดับการบันทึกของตนเองที่สามารถเปิดใช้งานและปิดการใช้งานในขณะใช้งานจริง

public @interface Trace {
  boolean showParameters();
}

@Aspect
public class TraceAspect {
  [...]
  @Around("tracePointcut() && @annotation(trace) && !within(TraceAspect)")
  public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) {

    Object result;
    // initilize timer

    try { 
      result = jp.procced();
    } finally { 
      // calculate execution time 
    }

    return result;
  }
  [...]
}

13

JEP 230: Microbenchmark Suite

FYI, JEP 230: Microbenchmark Suiteเป็นโครงการOpenJDKเพื่อ:

เพิ่มชุดพื้นฐานของ microbenchmarks ในซอร์สโค้ด JDK และทำให้ง่ายสำหรับนักพัฒนาในการเรียกใช้ microbenchmarks ที่มีอยู่และสร้างใหม่

คุณลักษณะนี้จะมาถึงในJava 12

Java Microbenchmark Harness (JMH)

สำหรับ Java เวอร์ชันก่อนหน้าดูที่โครงการJava Microbenchmark Harness (JMH)ที่ใช้ JEP 230


11

รหัสที่ดีจริงๆ

http://www.rgagnon.com/javadetails/java-0585.html

import java.util.concurrent.TimeUnit;

long startTime = System.currentTimeMillis();
........
........
........
long finishTime = System.currentTimeMillis();

String diff = millisToShortDHMS(finishTime - startTime);


  /**
   * converts time (in milliseconds) to human-readable format
   *  "<dd:>hh:mm:ss"
   */
  public static String millisToShortDHMS(long duration) {
    String res = "";
    long days  = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration)
                   - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration)
                     - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration)
                   - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    if (days == 0) {
      res = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }
    else {
      res = String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
    }
    return res;
  }

3
ที่จริงคำถามคือวิธีการคำนวณระยะเวลาที่ใช้วิธีไม่ใช่วิธีการจัดรูปแบบ อย่างไรก็ตามคำถามนี้ค่อนข้างเก่า (เกือบสี่ปี!) พยายามหลีกเลี่ยงการสร้างเธรดเก่าอีกครั้งเว้นแต่ว่าการตอบกลับจะเพิ่มสิ่งใหม่และสำคัญกว่าการตอบกลับที่มีอยู่
— Leigh

1
และเพื่อเพิ่มlong millis = TimeUnit.MILLISECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); if (days == 0) { res = String.format("%02d:%02d:%02d.%02d", hours, minutes, seconds, millis); } else { res = String.format("%dd%02d:%02d:%02d.%02d", days, hours, minutes, seconds, millis); }
— มิลลิวินาที

10

คุณสามารถใช้Perf4j ยูทิลิตี้ที่ยอดเยี่ยมมาก การใช้งานง่าย

String watchTag = "target.SomeMethod";
StopWatch stopWatch = new LoggingStopWatch(watchTag);
Result result = null; // Result is a type of a return value of a method
try {
    result = target.SomeMethod();
    stopWatch.stop(watchTag + ".success");
} catch (Exception e) {
    stopWatch.stop(watchTag + ".fail", "Exception was " + e);
    throw e; 
}

ข้อมูลเพิ่มเติมสามารถพบได้ในคู่มือนักพัฒนาซอฟต์แวร์

แก้ไข: โครงการดูเหมือนจะตาย


1
Perf4j ยังสามารถสร้างความสุขสถิติ
— Paaske

8
new Timer(""){{
    // code to time 
}}.timeMe();



public class Timer {

    private final String timerName;
    private long started;

    public Timer(String timerName) {
        this.timerName = timerName;
        this.started = System.currentTimeMillis();
    }

    public void timeMe() {
        System.out.println(
        String.format("Execution of '%s' takes %dms.", 
                timerName, 
                started-System.currentTimeMillis()));
    }

}

1
ม้วนคลาสที่เรียบง่ายของคุณเองเป็นทางเลือกที่ดีเมื่อคุณมีระบบการสร้างและติดตั้ง OTS แบบพึ่งพาแล้วและไม่ต้องการรบกวนการดึงในแพ็คเกจ OTS อื่นที่มีคลาสตัวจับเวลายูทิลิตี้
— Ogre Psalm33

7

โดยทั่วไปฉันจะทำสิ่งต่าง ๆ นี้ แต่พิจารณาว่าการรวบรวมฮอตสปอตทำงานอย่างไรถ้าคุณต้องการได้ผลลัพธ์ที่ถูกต้องคุณต้องทำการวัดสองสามครั้งแรกและตรวจสอบให้แน่ใจว่าคุณกำลังใช้วิธีในโลกแห่งความเป็นจริง (อ่านเฉพาะแอปพลิเคชัน)

หาก JIT ตัดสินใจรวบรวมตัวเลขของคุณจะแตกต่างกันอย่างมาก ดังนั้นจงระวัง


7

การใช้ AOP / AspectJ และ@Loggableหมายเหตุประกอบจากjcabi-problemsคุณสามารถทำได้ง่ายและกะทัดรัด:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

การเรียกใช้วิธีนี้ทุกครั้งจะถูกส่งไปยังระบบบันทึกการทำงาน SLF4J พร้อมDEBUGระดับการบันทึก และทุกข้อความบันทึกจะมีเวลาดำเนินการ


7

Spring จัดเตรียมยูทิลิตี้คลาส org.springframework.util.StopWatchตาม JavaDoc:

นาฬิกาจับเวลาแบบง่ายช่วยให้สามารถกำหนดเวลาของงานจำนวนหนึ่งเปิดเผยเวลาทำงานทั้งหมดและเวลาทำงานสำหรับแต่ละงานที่มีชื่อ

การใช้งาน:

StopWatch stopWatch = new StopWatch("Performance Test Result");

stopWatch.start("Method 1");
doSomething1();//method to test
stopWatch.stop();

stopWatch.start("Method 2");
doSomething2();//method to test
stopWatch.stop();

System.out.println(stopWatch.prettyPrint());

เอาท์พุท:

StopWatch 'Performance Test Result': running time (millis) = 12829
-----------------------------------------
ms     %     Task name
-----------------------------------------
11907  036%  Method 1
00922  064%  Method 2

ด้วยมุมมอง:

@Around("execution(* my.package..*.*(..))")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    Object retVal = joinPoint.proceed();
    stopWatch.stop();
    log.info(" execution time: " + stopWatch.getTotalTimeMillis() + " ms");
    return retVal;
}

เป็นไปได้ไหมที่จะใช้สิ่งนี้กับ AspectJ?
— zygimantus

7

ฉันได้เขียนวิธีการที่จะพิมพ์เวลาดำเนินการของวิธีการในรูปแบบที่อ่านได้มาก ตัวอย่างเช่นในการคำนวณแฟคทอเรียลที่ 1 ล้านจะใช้เวลาประมาณ 9 นาที ดังนั้นเวลาดำเนินการจะถูกพิมพ์เป็น:

Execution Time: 9 Minutes, 36 Seconds, 237 MicroSeconds, 806193 NanoSeconds

รหัสอยู่ที่นี่:

public class series
{
    public static void main(String[] args)
    {
        long startTime = System.nanoTime();

        long n = 10_00_000;
        printFactorial(n);

        long endTime = System.nanoTime();
        printExecutionTime(startTime, endTime);

    }

    public static void printExecutionTime(long startTime, long endTime)
    {
        long time_ns = endTime - startTime;
        long time_ms = TimeUnit.NANOSECONDS.toMillis(time_ns);
        long time_sec = TimeUnit.NANOSECONDS.toSeconds(time_ns);
        long time_min = TimeUnit.NANOSECONDS.toMinutes(time_ns);
        long time_hour = TimeUnit.NANOSECONDS.toHours(time_ns);

        System.out.print("\nExecution Time: ");
        if(time_hour > 0)
            System.out.print(time_hour + " Hours, ");
        if(time_min > 0)
            System.out.print(time_min % 60 + " Minutes, ");
        if(time_sec > 0)
            System.out.print(time_sec % 60 + " Seconds, ");
        if(time_ms > 0)
            System.out.print(time_ms % 1E+3 + " MicroSeconds, ");
        if(time_ns > 0)
            System.out.print(time_ns % 1E+6 + " NanoSeconds");
    }
}

6

มีสองวิธีในการทำเช่นนั้น ปกติแล้วฉันจะกลับไปใช้สิ่งนี้:

long start = System.currentTimeMillis();
// ... do something ...
long end = System.currentTimeMillis();

หรือสิ่งเดียวกันกับ System.nanoTime ();

สำหรับบางสิ่งที่เพิ่มเติมเกี่ยวกับการเปรียบเทียบของสิ่งต่าง ๆ ดูเหมือนจะเป็นสิ่งนี้: http://jetm.void.fm/ไม่เคยลองเลย


6

คุณสามารถใช้ห้องสมุดMetricsซึ่งมีเครื่องมือวัดต่างๆ เพิ่มการพึ่งพา:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-core</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

และกำหนดค่าให้กับสภาพแวดล้อมของคุณ

วิธีการสามารถเพิ่มความคิดเห็นด้วย@Timed :

@Timed
public void exampleMethod(){
    // some code
}

หรือชิ้นส่วนของรหัสห่อด้วยตัวจับเวลา :

final Timer timer = metricsRegistry.timer("some_name");
final Timer.Context context = timer.time();
// timed code
context.stop();

ตัวชี้วัดโดยรวมสามารถส่งออกไปยังคอนโซล, JMX, CSV หรืออื่น ๆ

@Timed ตัวอย่างเอาต์พุตเมทริก:

com.example.ExampleService.exampleMethod
             count = 2
         mean rate = 3.11 calls/minute
     1-minute rate = 0.96 calls/minute
     5-minute rate = 0.20 calls/minute
    15-minute rate = 0.07 calls/minute
               min = 17.01 milliseconds
               max = 1006.68 milliseconds
              mean = 511.84 milliseconds
            stddev = 699.80 milliseconds
            median = 511.84 milliseconds
              75% <= 1006.68 milliseconds
              95% <= 1006.68 milliseconds
              98% <= 1006.68 milliseconds
              99% <= 1006.68 milliseconds
            99.9% <= 1006.68 milliseconds

5

หากคุณต้องการเวลานาฬิกาแขวน

long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;

5

ดังที่คำสั่ง "skaffman" ใช้ AOP หรือคุณสามารถใช้การประมวลผลแบบไบต์ไทม์ของการทอเช่นเดียวกับเครื่องมือครอบคลุมวิธีการทดสอบหน่วยที่ใช้ในการเพิ่มข้อมูลเวลาให้กับวิธีที่เรียกใช้อย่างโปร่งใส

คุณสามารถดูรหัสที่ใช้โดยเครื่องมือเครื่องมือโอเพนซอร์ซเช่น Emma ( http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0 ) เครื่องมือครอบคลุม opensource อื่น ๆ คือhttp://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download http://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download

หากคุณสามารถทำสิ่งที่คุณต้องการได้ในที่สุด แบ่งปันกลับกับชุมชนที่นี่ด้วยภารกิจ / ขวดของคุณ


4
long startTime = System.currentTimeMillis();
// code goes here
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime; // elapsed time in milliseconds

4

ฉันแก้ไขโค้ดจากคำตอบที่ถูกต้องเพื่อให้ได้ผลลัพธ์ในไม่กี่วินาที:

long startTime = System.nanoTime();

methodCode ...

long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / (Math.pow(10, 9));
Log.v(TAG, "MethodName time (s) = " + duration);

4

คุณสามารถใช้คลาสนาฬิกาจับเวลาจากโครงการแกนกลางของสปริง:

รหัส:

StopWatch stopWatch = new StopWatch()
stopWatch.start();  //start stopwatch
// write your function or line of code.
stopWatch.stop();  //stop stopwatch
stopWatch.getTotalTimeMillis() ; ///get total time

เอกสารประกอบสำหรับนาฬิกาจับเวลา: นาฬิกาจับเวลา แบบง่ายช่วยให้สามารถกำหนดเวลาของงานจำนวนมากเปิดเผยเวลาทำงานทั้งหมดและเวลาทำงานสำหรับแต่ละงานที่มีชื่อ ปกปิดการใช้ System.currentTimeMillis () ปรับปรุงการอ่านรหัสแอปพลิเคชันและลดโอกาสในการเกิดข้อผิดพลาดในการคำนวณ โปรดทราบว่าวัตถุนี้ไม่ได้รับการออกแบบให้ปลอดภัยต่อเธรดและไม่ได้ใช้การซิงโครไนซ์ คลาสนี้โดยปกติจะใช้เพื่อตรวจสอบประสิทธิภาพในระหว่างการพิสูจน์แนวคิดและในการพัฒนาแทนที่จะเป็นส่วนหนึ่งของแอปพลิเคชันการผลิต


3

คุณสามารถลองด้วยวิธีนี้หากต้องการทราบเวลา

long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));    

3

ตกลงนี่เป็นคลาสแบบง่าย ๆ ที่จะใช้สำหรับช่วงเวลาแบบง่าย ๆ ของฟังก์ชั่นของคุณ มีตัวอย่างด้านล่าง

public class Stopwatch {
    static long startTime;
    static long splitTime;
    static long endTime;

    public Stopwatch() {
        start();
    }

    public void start() {
        startTime = System.currentTimeMillis();
        splitTime = System.currentTimeMillis();
        endTime = System.currentTimeMillis();
    }

    public void split() {
        split("");
    }

    public void split(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Split time for [" + tag + "]: " + (endTime - splitTime) + " ms");
        splitTime = endTime;
    }

    public void end() {
        end("");
    }
    public void end(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Final time for [" + tag + "]: " + (endTime - startTime) + " ms");
    }
}

ตัวอย่างการใช้งาน:

public static Schedule getSchedule(Activity activity_context) {
        String scheduleJson = null;
        Schedule schedule = null;
/*->*/  Stopwatch stopwatch = new Stopwatch();

        InputStream scheduleJsonInputStream = activity_context.getResources().openRawResource(R.raw.skating_times);
/*->*/  stopwatch.split("open raw resource");

        scheduleJson = FileToString.convertStreamToString(scheduleJsonInputStream);
/*->*/  stopwatch.split("file to string");

        schedule = new Gson().fromJson(scheduleJson, Schedule.class);
/*->*/  stopwatch.split("parse Json");
/*->*/  stopwatch.end("Method getSchedule"); 
    return schedule;
}

ตัวอย่างของเอาต์พุตคอนโซล:

Split time for [file to string]: 672 ms
Split time for [parse Json]: 893 ms
Final time for [get Schedule]: 1565 ms

3

ใน Java 8 คลาสใหม่ที่ชื่อว่าInstantถูกนำมาใช้ ตามเอกสาร:

แสดงให้เห็นถึงการเริ่มต้นของเสี้ยววินาทีบนเส้นเวลาทันที คลาสนี้มีประโยชน์สำหรับการสร้างการประทับเวลาเพื่อแสดงเวลาของเครื่อง ช่วงของการโต้ตอบแบบทันทีจำเป็นต้องมีการจัดเก็บจำนวนที่มากกว่าความยาว เพื่อให้บรรลุสิ่งนี้คลาสจะทำการจัดเก็บแบบ epoch-seconds และ int ที่แทน nanosecond-of-second ซึ่งจะอยู่ระหว่าง 0 ถึง 999,999,999 ยุควินาทีถูกวัดจากยุค Java มาตรฐานของ 1970-01-01T00: 00: 00Z โดยที่ instants หลังจากยุคนั้นมีค่าเป็นบวกและ instants ก่อนหน้านี้มีค่าลบ สำหรับทั้งยุควินาทีและส่วนนาโนวินาทีค่าที่ใหญ่กว่าจะตามมาในเส้นเวลาเสมอกว่าค่าที่เล็กกว่า

สามารถใช้เป็น:

Instant start = Instant.now();
try {
    Thread.sleep(7000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

PT7.001Sมันพิมพ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.