可用数组实现轻量级抢占式任务调度器:按优先级升序维护任务数组,新任务插入时线性查找定位,抢占在插入/让出/时间片到期时比较队首与当前任务优先级触发,上下文通过对象深拷贝隔离。

可以用数组模拟一个轻量级的抢占式任务调度器,关键在于维护任务顺序、判断是否需要抢占、以及保存和恢复上下文变量。它不依赖操作系统内核,适合嵌入式、脚本调度或教学演示场景。
用数组组织任务并按优先级排序
数组本身不带排序能力,需手动维持“高优先级在前”的顺序。优先级数值越小代表越紧急(如 Linux 的 PRI 规则),插入新任务时从头遍历,找到第一个优先级 ≥ 当前任务的位置插入,保证数组始终有序。
- 定义任务结构:每个元素为对象,含 id、priority(整数,越小越急)、state(如 "ready" / "running" / "done")、context(键值对形式的变量快照)
- 插入逻辑示例(伪代码):
for i in 0..tasks.length:
if tasks[i].priority >= newTask.priority:
insert at i
break - 避免每次插入都重排整个数组;仅做一次线性查找 + 一次切片插入,时间复杂度 O(n),对几十个任务足够高效
抢占判断与触发时机
抢占不是持续扫描,而是在特定事件点检查:新任务加入、当前任务让出、或固定时间片到期。此时只需比较“就绪队列首任务”和“正在运行任务”的优先级。
- 设 currentTask 为当前执行中的任务(可为 null)
- 当新任务插入后,若 currentTask === null 或 tasks[0].priority ,说明更高优任务已就绪,应立即抢占
- 无需中断硬件支持——在用户态通过函数调用切换即可,例如调用 switchContext(newTask, currentTask)
上下文变量的保存与恢复
上下文不是寄存器状态,而是业务层关心的变量集合。用 plain object 存储,切换时深拷贝或引用交换,确保前后任务互不污染。
- 每个任务的 context 字段初始化为所需变量,如:
{ count: 0, lastResult: null, config: { timeout: 3000 } } - 切换函数核心逻辑:
if (currentTask) currentTask.context = saveCurrentState();
restoreToTask(tasks[0]);
currentTask = tasks[0]; - saveCurrentState() 可读取当前执行环境中的变量;restoreToTask() 则把目标任务 context 的字段赋值回全局/作用域变量,或注入到其执行函数的参数中
一个可运行的 JavaScript 实战片段
以下代码在浏览器或 Node.js 中直接执行,演示三任务抢占与计数器上下文隔离:
let tasks = [];
let currentTask = null;
let globalCounter = 0;
function addTask(id, priority, fn) {
const task = { id, priority, fn, context: { counter: 0 } };
// 插入并保持升序(小数字优先)
let inserted = false;
for (let i = 0; i
if (tasks[i].priority > priority) {
tasks.splice(i, 0, task);
inserted = true;
break;
}
}
if (!inserted) tasks.push(task);
checkPreemption();
}
function checkPreemption() {
if (tasks.length === 0) return;
const top = tasks[0];
if (!currentTask || top.priority
if (currentTask) {
currentTask.context.counter = globalCounter;
}
globalCounter = top.context.counter;
currentTask = top;
console.log(`→ Switched to task ${top.id}, counter=${globalCounter}`);
}
}
// 启动调度循环(简化版)
function runNext() {
if (!currentTask) return;
globalCounter++;
currentTask.fn(globalCounter);
if (globalCounter >= 3) {
console.log(`✓ Task ${currentTask.id} done`);
tasks.shift();
currentTask = null;
checkPreemption();
}
}
addTask('A', 10, (c) => console.log('A:', c)); // 低优
addTask('B', 1, (c) => console.log('B:', c)); // 高优 → 立即抢占
addTask('C', 5, (c) => console.log('C:', c)); // 中优
runNext(); // 输出 B:1
runNext(); // 输出 B:2
runNext(); // 输出 B:3 → 完成,自动切到 C










