35岁大厂程序员上岸武汉体制内,收入从百万年薪锐减到十几万后,妻子嫌弃他没上进心。网友:这种老公,离!
刚看到个贴子,说一位35岁大厂程序员,上岸武汉体制内,从百万年薪变成一年十几万,结果老婆嫌他没上进心。底下不少网友直接一句:这种老公,离!
网友喊“离”,说实话有点上头了。婚姻又不是只看工资条,多赚是一种责任,少犯错、活得久,也是另一种责任。
真正的问题是:这事两个人有没提前算清账、谈明白预期?是一起做的选择,还是他一个人拍脑袋?
在我看来,家庭更像合伙开公司:有人负责冲锋,有人负责稳住盘子,可以换赛道,但别瞒着队友。比起一句“离”,我更希望他们能坐下来,把未来十年的钱、健康、孩子,一起摊开聊清楚,这才叫上进。
面试题:每台机器的进程平均运行时间
昨天晚上十一点多,我在公司楼下抽烟,手机一震,是我们组那个小李:“东哥,你说监控系统里面那堆进程日志,有没有简单一点的算⼀下,每台机器平均一个进程跑多久啊?老板要个报表。” 我当时脑子已经半糊涂了,但这事儿其实挺典型的一个小算法题。
你可以想象这样一串数据,每条都长得差不多:
machineId:机器编号,比如 1、2、3 processId:进程编号 startTime:开始时间戳(毫秒) endTime:结束时间戳(毫秒)
也就是一行行类似这样的记录:
机器A,进程p1,从 1000ms 跑到 3000ms
机器A,进程p2,从 2000ms 跑到 2600ms
机器B,进程q1,从 1500ms 跑到 4500ms
...
问题就变成一句话:按机器分组,把这一台机器上所有进程的运行时长取平均值。
跟我之前做数据库压测那种“按库统计平均耗时”的活儿一个味道,只不过这次是按机器来聚合。
这种题要是你一上来就想各种“时间轴呀、排序呀、窗口呀”,基本就是自己吓自己。
最朴素那版思路就两件事:
每条记录先算出这个进程的运行时长: duration = endTime - startTime按 machineId 把这些 duration 累加起来,同时数一下有多少个进程,最后 avg = 总时长 / 进程数量
用人话说,就是: “这一台机器所有进程的用时都加一块儿,然后除一下个数。”
时间复杂度就是 O(n),一条记录只看一眼;空间复杂度大概是 O(m),m 是机器数量,一般也不算多。
小李当时就一句话:“你别跟我说思路,直接丢个方法给我。”那就写个简单点的版本:
import java.util.*;
publicclassMachineAvgRuntime{
// 一条进程记录
publicstaticclassProcessRecord{
privateint machineId;
private String processId;
privatelong startTime; // 毫秒时间戳
privatelong endTime; // 毫秒时间戳
publicProcessRecord(int machineId, String processId, long startTime, long endTime){
this.machineId = machineId;
this.processId = processId;
this.startTime = startTime;
this.endTime = endTime;
}
publicintgetMachineId(){
return machineId;
}
publiclonggetDuration(){
// 简单防御:如果 end 比 start 小,就当成 0
return Math.max(0, endTime - startTime);
}
}
// 核心方法:算每台机器的平均进程运行时间
publicstatic Map<Integer, Double> calcAvgRuntimePerMachine(List<ProcessRecord> records){
// key: machineId
// value[0]: 总时长之和,value[1]: 进程数量
Map<Integer, long[]> statMap = new HashMap<>();
for (ProcessRecord record : records) {
int machineId = record.getMachineId();
long duration = record.getDuration();
long[] stat = statMap.get(machineId);
if (stat == null) {
stat = newlong[2];
statMap.put(machineId, stat);
}
stat[0] += duration; // 累加总时长
stat[1] += 1; // 进程计数 +1
}
// 把结果转成平均值
Map<Integer, Double> result = new HashMap<>();
for (Map.Entry<Integer, long[]> entry : statMap.entrySet()) {
int machineId = entry.getKey();
long totalDuration = entry.getValue()[0];
long count = entry.getValue()[1];
if (count == 0) {
result.put(machineId, 0.0);
} else {
// 这里转 double,避免整型除法精度丢失
result.put(machineId, totalDuration * 1.0 / count);
}
}
return result;
}
// 随便写个 main 测一下
publicstaticvoidmain(String[] args){
List<ProcessRecord> list = new ArrayList<>();
// 机器 1 上两个进程:时长分别 2000 和 600
list.add(new ProcessRecord(1, "p1", 1000, 3000));
list.add(new ProcessRecord(1, "p2", 2000, 2600));
// 机器 2 上一个进程:时长 3000
list.add(new ProcessRecord(2, "q1", 1500, 4500));
Map<Integer, Double> avg = calcAvgRuntimePerMachine(list);
System.out.println(avg); // 比如:{1=1300.0, 2=3000.0}
}
}
这个实现比较无脑,但胜在清楚:
用 Map<Integer, long[]>做统计容器,不额外建一堆类long[0]存总时长,long[1]存数量,最后统一扫一遍算平均值最外层结果再转成 Map<Integer, Double>,给前端图表、报表用都还行
行了,我这边咖啡也凉了,就先这样,小李那报表后来顺利交差,你要是真线上要用,记得别在 SQL 里一层层嵌套聚合干这个,用程序扫一遍,稳。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html