Такта дела, для достижения цели!
let map = new Map();
function doAction(uid) {
map.set(uid, new Date().getTime());
}
setInterval(function(){
for(let uid of map.keys()) {
if(+new Date() - map.get(uid) > 30000) {
map.delete(uid);
console.log(`${uid}超过30s未做任何操作,设置为离线!`);
}
}
}, 10000);
Слабые стороны программы:
- низкая эффективность. Записи, которые были выполнены, все равно будут сканироваться (но не будут отображаться в результирующем наборе), и будет много повторяющихся вычислений;
- Плохая своевременность. Временная ошибка зависит от интервала опроса, если интервал слишком мал, количество повторных сканирований будет выше, а эффективность станет ниже.
обработка синхронизации
Каждый раз, когда приходит задача, запускается таймер, достигается время таймера и выполняется соответствующая обработка;
function doAction(uid) {
map.set(uid, new Date().getTime());
setTimeout(function() {
console.log(`${uid}超过30s未做任何操作,设置为离线!`);
}, 30000);
}
Слабые стороны программы:
- Слишком большое количество таймингов может привести к чрезмерному использованию памяти, что может легко привести к сбоям.
Обработка циклической очереди
структура данных:
- круговая очередьListLoop, например, вы можете создать слот**круговую очередь**, содержащую 0–30 (по сути, массив);
- Коллекция задач на каждом кольцеSlot, каждый слот на кольце являетсяSet;
- Запишите каждую задачу, соответствующую слотуMapсобирать;
Процесс реализации:
первый шаг:0->1->2->3…->29->30->0…
CURRORTSLOTINDEX указатель для идентификации вновь обнаруженного через слот;
Шаг 2:
третий шаг:
четвертый шаг:Добавьте uid обратно в новый слот (последний слот, на который указывает указатель CurrentSlotIndex), потому что этот слот будет сканироваться таймером через 30 с.
пятый шаг:Обновите карту и сбросьте значение индекса слота, соответствующего uid
// new Array(31).fill(new Set())
// No,数组中所有Set集合为同一个
let listLoop = new Array(31),
map = new Map(), // 记录每个uid的slotIndex
currentSlotIndex = 1; // 当前要检测的slot
function doAction(uid) {
// 如果循环队列中已存在该uid,需要先干掉,重新计时
let slotIndex = map.get(uid);
slotIndex && listLoop[slotIndex].delete(uid);
// 将该uid重现添加到循环队列中
// 周期31,新插入的置入当前的后一个(即,30s后可以扫描到它)
// 更新map中这个uid的最新slotIndex
slotIndex = currentSlotIndex - 1;
listLoop[slotIndex] = listLoop[slotIndex] ?
listLoop[slotIndex].add(uid) : new Set().add(uid);
map.set(uid, slotIndex);
}
// 每秒钟移动一个slot,这个slot对应的set集合中所有uid都为超时
// 如果所有slot对应的set集合都为空,则表示没有uid超时
setInterval(function() {
var slotSet = listLoop[currentSlotIndex];
if(slotSet && slotSet.size > 0) {
for(let uid of slotSet.values()) {
// 执行完的uid从map集合中剔除
map.delete(uid);
console.log(`<${uid}>超过30s未做任何操作,设置为离线!`);
}
// 置空该集合
slotSet.clear();
}
// 指标继续+1
currentSlotIndex = (++currentSlotIndex) % 31;
}, 1000);
// 思路、注意Map集合的内心移除情况。
Преимущества схемы:
- Нет необходимости повторно опрашивать все заказы, высокая эффективность
- Без повторного выполнения, один заказ, задание выполняется только один раз
- Хорошая эффективность, точность до секунды (управление частотой движения таймера может контролировать точность)
Обратитесь к статье:Задача на 10 Вт, как эффективно запустить тайм-аут,1 минута для достижения функции «задержанного сообщения»
учиться по аналогии
Вышеприведенная презентация описывает бизнес-сценарий черезкруговая очередьМы также можем обрабатывать множество подобных сценариев.
- После того, как заказ программного обеспечения для вызова такси будет завершен, если пользователь не прокомментировал, ему будет автоматически присвоен 5 звезд через 48 часов;
- Если пользователь продукта данных изменит настройки, они вступят в силу через 1 час;
- ...