【问题标题】:Measure runtime of a method handled by bukkit.event.Listener测量由 bukkit.event.Listener 处理的方法的运行时间
【发布时间】:2021-07-12 22:06:32
【问题描述】:

我需要以毫秒 (#.### ms) 为单位准确测量 void 方法运行所需的准确时间,而测量不会影响结果。

通常我会简单地做这样的事情:

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

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

这行不通,因为我的代码从不直接调用该方法;它只定义了它。

import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;

public class BlockListener implements Listener {

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onPlace(BlockPlaceEvent event) {

    //...
    }
}

在我正在开发的这个 Minecraft Bukkit 服务器中的某些方法的上下文中,1 毫秒很重要,这意味着我需要高精度来测量并优化对时间敏感的方法。

那么,在方法中添加任何代码肯定会影响方法的运行时间吗?

衡量这一点的最佳方法是什么?请和谢谢你

使用 ProtocolLib (1.16.5) 运行纸张/Spigot

【问题讨论】:

    标签: java performance listener bukkit eventhandler


    【解决方案1】:

    绩效衡量总是会影响您的绩效,这就是为什么我建议将此功能设为可切换的原因。基于this answer,每个方法调用System.nanoTime() 两次大约需要200 个CPU 时钟周期,这不是很大的开销。

    但是在测量了执行时间之后,你需要把它保存在某个地方或者打印一个日志。通常,I/O 操作是最昂贵的,因此最好避免在您的方法中阻塞输出。为此,您可以利用java.util.concurrent.BlockingQueue 或线程安全管道的其他实现(如DisruptorJCTools)并将捕获的结果记录在单独的守护线程中。

    实施方案

    public class ListenerPerformanceAuditor implements Listener {
    
        private final BlockingQueue<Long> executionTimeQueue;
        private final Listener auditedListener;
    
        public ListenerPerformanceAuditor(
                Listener auditedListener,
                BlockingQueue<Long> executionTimeQueue
        ) {
            this.auditedListener = auditedListener;
            this.executionTimeQueue = executionTimeQueue;
        }
    
        public void onPlace(BlockPlaceEvent event) {
            long startTime = System.nanoTime();
            auditedListener.onPlace(event);
            long endTime = System.nanoTime();
    
            long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.
            if(!executionTimeQueue.offer(duration)) {
                // if measuring each and every request isn't necessary,
                // this block can be eliminated, otherwise add error handling logic
            }
        }
    }
    
    

    【讨论】:

    • 用 println() 打印到标准输出怎么样?这大约需要多长时间?是否会像在方法中获取 nanoTime 的延迟一样微不足道?
    • 打印到控制台的性能与单线程应用程序中的ArrayBlockingQueue#offer 性能相当,但System.out.println 是一种同步操作,当多个线程时可能会导致多线程系统中的性能下降尝试写入控制台。另外,您可以直接在ListenerPerformanceAuditor 中打印,但是在线程池中,因此不需要队列并且性能保持稳定
    猜你喜欢
    • 2013-07-14
    • 2011-04-29
    • 2022-07-29
    • 2020-12-06
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2012-05-14
    • 2016-09-01
    相关资源
    最近更新 更多