Python技术迷

某字节员工直言,做程序员久了,发现大家都有个共同之处,就是家庭条件真的都不太好,不绝对,但是不少人都是这种情况

刚看到个贴子,说是某字节员工直言:程序员干久了,会发现一个共性——很多人家庭条件一般,甚至可以说不太好。

Image

我觉得这话吧,其实挺真实。编程这条路,说白了就是门“技术逆袭”的赛道。家境优渥的孩子,可能更愿意去投身金融、创业或者有资源的行业;而很多程序员,是靠一台电脑、一堆代码硬啃出来的,算是最能“用实力换饭吃”的职业。

网友们有人调侃“怪不得卷成这样”,也有人说“这才是普通家庭孩子最公平的赛道”。我比较认同后者,毕竟写代码是个拼逻辑和执行的事,背景影响小,努力和天赋能直接转化为收入。换句话说,这个行业对普通家庭孩子来说,反而是一条最靠谱的上升通道。【备注:文末可领最新资料】

面试题:统计实验的数量

昨天晚上十一点多,我在公司楼下嚼着冷掉的煎饼,小李蹭过来一句“东哥,咱那实验日志乱成一锅粥,怎么快速数今天到底做了几次实验啊?”我脑子里“咔”一下就有数了——别慌,先把问题说清楚再下手,对吧。

我们有一堆事件日志,像这样三列:timestamp, action, exp_id。action 只有两种:start / end。麻烦点在于: 1)事件可能乱序;2)同一个 exp_id 可能被重试,多次开始多次结束;3)有些开始没结束(崩了),有些结束没开始(补写的脏数据)。 目标很朴素:统计“有效实验次数”——也就是能被一对 start-end 正常配对的次数。另外顺手算下并发峰值、平均耗时,值了。

乱序最大的敌人,用排序解决。按 timestamp 升序把日志排好,接着给每个 exp_id 准备一个“小栈”(其实就是列表):

  • 来一条 start,把开始时间压进去;
  • 来一条 end,如果栈里有对应开始时间,就弹出一条,记一次有效实验,顺便算时长;如果栈是空的,说明这是“孤儿 end”,直接忽略。 同时我们维护一个全局计数 running,遇到 start +1,匹配成功的 end -1,用它滚动记录并发峰值。
from typing import List, Tuple, Dict
from collections import defaultdict

Log = Tuple[int, str, str]  # (timestamp, action, exp_id)

defcount_experiments(logs: List[Log]):
# 1) 排序:时间升序
    logs_sorted = sorted(logs, key=lambda x: x[0])

# 2) 每个实验ID一个“开始时间栈”
    starts: Dict[str, List[int]] = defaultdict(list)

    valid_cnt = 0
    durations = []  # 收集每次有效实验的耗时(秒)
    running = 0
    peak_concurrency = 0

for ts, action, eid in logs_sorted:
if action == "start":
            starts[eid].append(ts)
            running += 1
if running > peak_concurrency:
                peak_concurrency = running
elif action == "end":
if starts[eid]:               # 有可配对的开始
                t0 = starts[eid].pop()
                valid_cnt += 1
                durations.append(ts - t0 if ts >= t0 else0)
                running = max(0, running - 1)
else:
# 孤儿 end,忽略即可
pass
else:
# 未知动作,按脏数据忽略
pass

    avg_duration = (sum(durations) / len(durations)) if durations else0.0
# 还留在 starts 里的开始事件就是未完成实验,按需求这里不记入有效次数

return {
"valid_experiments": valid_cnt,
"peak_concurrency": peak_concurrency,
"avg_duration": avg_duration,
"unfinished_by_id": {eid: len(stk) for eid, stk in starts.items() if stk}
    }

# 小例子,昨天中午抓的那点样本
if __name__ == "__main__":
    sample = [
        (12, "start", "A"),
        (15, "start", "A"),   # A 第二次重试
        (16, "end",   "A"),   # 配到 15
        (20, "start", "B"),
        (25, "end",   "A"),   # 配到 12
        (26, "end",   "B"),
        (30, "end",   "C"),   # 孤儿 end
        (35, "start", "C")    # 未完成
    ]
    print(count_experiments(sample))

跑这段,你会拿到四个关键信息:

  • valid_experiments:有效实验总数(配对成功的次数);
  • peak_concurrency:最高并发有多少个实验在跑;
  • avg_duration:成功实验的平均耗时;
  • unfinished_by_id:哪些 exp_id 还残留未完成(可能是挂了)。

时间复杂度其实挺朴素:排序是 O(n log n),后面一趟扫 O(n),整体就 O(n log n);空间就是给每个 exp_id 开个小栈,O(k)。 异常数据怎么处置?这玩意儿别纠结:孤儿 end 忽略,孤儿 start 视为未完成;如果你们审计严一点,也可以把这些都记到告警里。 还有人问“能不能只看今天?”那就在进函数前把 timestamp 用一天的范围先 filter 一下,别把夜里两点的脏数据算进来,容易挨骂。

行了我先去泡杯茶,谁要是要把它接到 Kafka 消费里头,直接在回调里喂 logs 就行,别忘了开窗口聚合,不然内存顶不住,嗯就这样先。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领