异步队列:最经典的编程面试题,AI也犯难!


《异步队列——我最爱的编程面试题(AI能破解它吗?)》  作者:David Gomes

过去7年多,我一直在用这道编程面试题考人,简直是我的心头好!这题是我从好基友Jeremy Kaplan和Carl Sverre那儿继承来的(我觉得是Carl发明的)。我们几个在不同公司至少考过500-1000次,现在你去搜"异步队列面试",满屏都是相关结果。所以我觉得写这篇博客应该没问题。

今天主要想唠唠为啥我这么爱这道题,顺便看看现在AI能做到什么程度(当然啦,AI进步飞快,可能过段时间这文章就过时了)。

️ 面试开场白(故事版)
想象我们在开发一个网页应用,这个客户端要和服务器通信。但这个服务器是个脆皮鸡!同时处理多个请求就会挂掉。于是我们决定在客户端做手脚,确保服务器同一时间最多只处理一个请求(假设是单服务器单客户端的情况)。

关键点来了:我们的客户端是单线程的!可以用JavaScript(天然单线程)或者其他语言(伪代码也行),但单线程这个设定很重要。

现在代码库里到处都是这样的发送函数:

typescript
declare function send

(
    payload: P,
    callback: () => void
): void;

这个send函数是个黑盒子,我们不用管它具体咋实现的。它干的事就是:把数据发给服务器,等服务器处理完(不管成功失败)就执行回调。

现在要新写个sendOnce函数替换它:

typescript
declare function sendOnce

(
    payload: P,
    callback: () => void
): void;

这个函数得保证:任何时候服务器最多只处理一个请求!

错误示范来了:

javascript
let requestQueue = [];

function sendOnce

(payload: P, callback: () => void) {
    //...省略实现细节...
}

这个版本有bug:如果连续快速调用sendOnce,就会违反"一次只发一个"的原则。

✅ 正确解法需要两个东西:
1. 请求队列
2. 处理状态标记isProcessing

javascript
let isProcessing = false;
let requestQueue = [];

function sendOnce(payload, callback) {
    requestQueue.push({ payload, callback });
    if (!isProcessing) processNextRequest();
}

function processNextRequest() {
    if (requestQueue.length === 0) {
        isProcessing = false;
        return;
    }
    //...后续处理...
}

这道题妙就妙在能考察:
- 能不能理清复杂的标志位逻辑?
- 能不能想到回调函数的正确包裹方式?
- 会不会被JavaScript单线程特性坑到?(很多新手会写while循环阻塞线程)

深入面试环节

等候选人搞定基础版,就可以加难度了!比如新增参数:

typescript
declare function sendOnce

(
    payload: P,
    callback: () => void,
    minDelayMs: number // 新增:延迟发送
): void;

解法很简单——用setTimeout包起来就行。但这里能看出候选人:
- 面对新需求时的应变能力
- 对单线程环境的理解(很多人会用假sleep卡线程)

终极挑战

这才是区分菜鸟和大神的地方!可以要求:
1. 实现定时发送的sendMany
2. 添加取消请求功能
3. 失败重试机制
4. 写测试用例!
5. 升级成完整AsyncQueue类,支持请求优先级...

AI能搞定吗?

现在用Claude Sonnet 4.0这种级别的AI,在正确提示下确实能解出基础版(连延迟发送都能搞定)。不过代码有点绕,需要反复提示才能简化。复杂需求就容易出bug了。

我的建议是:应该允许候选人用AI!现在不用AI写代码的程序员越来越少了。高手会这样操作:
1. 用AI自动补全
2. 快速准确地审查AI生成的代码
3. 用AI辅助写测试用例

这反而能考察候选人的"AI协同能力"——毕竟能用好新工具也是实力的一部分!