You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

System.nanoTime()计算异常?FTP客户端耗时统计不符问题排查

问题分析:System.nanoTime()统计耗时与实际不符的原因及解决办法

嘿,我看了你代码里的问题,这事儿其实是任务重试时的状态变量没重置导致的,咱们一步步拆解清楚:

问题成因

先理清楚你的代码逻辑里的坑:

  1. 你用了成员变量starttimestartflag来记录开始时间,而且startflag在第一次赋值starttime后就被设为false了。
  2. 所有catch块里都调用了start()方法——我猜这个方法是用来重启你的AsyncTask对吧?
  3. 当程序因为连接异常(比如UnknownHostException)重试时,startflag还是false,所以新任务不会重新赋值starttime,一直用第一次任务启动时的旧值。
  4. 最后某次任务成功传输完成(finflag=true)时,endtime是这次成功任务的结束时间,用它减去第一次任务的starttime,自然就把中间所有重试等待的时间都算进去了——这就是为什么统计出来是18秒,但实际成功传输只用了2秒。

另外还有个小问题:endtime放在doInBackground的最末尾,不管任务成功失败都会赋值,但只有成功时才会在onPostExecute里计算耗时。如果中间有多次失败重试,endtime会被覆盖,但starttime一直是第一次的旧值,结果就把所有重试的时间都累加进去了。

解决办法

咱们从两个核心点入手,确保每次任务的时间统计都是独立的:

1. 每次启动任务时重置所有状态变量

在你的start()方法里,把统计相关的变量全部重置,保证新任务从头开始统计:

public void start() {
    // 重置状态,彻底避免跨任务的状态污染
    startflag = true;
    finflag = false;
    starttime = 0;
    endtime = 0;
    // 这里放启动AsyncTask的代码,比如new YourAsyncTask().execute();
}

2. 把时间统计的时机调整到核心传输逻辑内

不要依赖startflag控制starttime的赋值,而是在成功建立连接并开始处理文件传输的瞬间记录开始时间,在传输完成(收到Finished)的瞬间记录结束时间:
修改doInBackground里的代码:

while(true) {
    socket = new Socket(ipadd, port);
    // 在这里直接记录开始时间,不用依赖外部状态变量
    starttime = System.nanoTime();
    
    br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    BufferedOutputStream bo = new BufferedOutputStream(socket.getOutputStream());
    PrintWriter pw = new PrintWriter(bo, true);
    file = br.readLine();

    if (file.equals("Finished")) {
        // ... 你的现有代码(读取datas、关闭流等)
        finflag=true;
        // 在这里记录结束时间,确保是传输完成的瞬间
        endtime = System.nanoTime();
        break;
    }
    // ... 文件传输的逻辑
}

3. (可选)避免成员变量跨任务污染

如果可以的话,把starttimeendtime改成doInBackground内的局部变量,只在当前任务中生效,这样就不会被其他重试任务影响了。不过因为你需要在onPostExecute里用这些值,所以可以把它们作为任务的返回值传递,或者用静态内部类封装任务状态。

验证修改

修改后,每次重试任务都会重新记录starttime,只有成功传输的那次任务的时间差会被计算,这样统计出来的时长就和实际传输时间完全一致了。

内容的提问来源于stack exchange,提问作者sumanth

火山引擎 最新活动