8.6. Демонстрация. Очереди для симуляции

Шаг 1

Частая задача, которую решают очереди — это симуляция каких-либо процессов. Обычно в рамках таких симуляций у нас есть какая-то система, на состояние которой мы как раз и симулируем влияние. А очередь обычно представляет собой набор данных, которые на эту систему влияют. В качестве примера давайте посмотрим на следующую задачу симуляции. Есть общие серверы для произведения вычислений на видеокартах, и обычно они полностью заняты. Чтобы не предлагать пользователям, которые хотят туда попасть, просто сделать это когда-то позднее, администраторы ввели очередь. Теперь каждый человек знает, сколько людей ему нужно пропустить вперёд, чтобы зайти на сервер. Серверы знают, сколько на них установлено доступных видеокарт и сколько в среднем каждый человек из очереди пользуется ими. Напишите функцию, которая будет прогнозировать для вставшего в очередь пользователя, сколько ему придётся прождать. Для упрощения будем считать, что первый человек в нашей симуляции зайдёт на сервер сразу же, как только займёт очередь. В этой задаче системой, на которую мы будем «влиять» является сервер, а данными, которые это делают, будут люди из очереди. В этой задаче данные из очереди не порождают данные в конец очереди. А очередь уже заранее определена: нам не нужно определять её из других данных (в отличие, например, от поиска в ширину, который мы недавно вспоминали).

import {test} from "./tester";

/*
Задача: смоделировать очередь людей (queue) на сервер из slots видеокарт
*/

function predict(queue, slots) {
  return 0;
}

test(predict([1, 2, 3], 1), 6);
test(predict([1, 2, 3], 2), 2);
test(predict([1, 2, 3], 3), 1);
test(predict([3, 2, 3], 3), 2);

Шаг 2

С системой и данными определились. Теперь нам нужно лишь понять, как именно данные будут влиять на систему. В нашем случае мы будем искать видеокарту с наименьшей занятостью: ту, которая будет занята меньшее количество времени. И симулировать, что следующий человек стоит в очереди на неё и занимает видеокарту столько времени, сколько ему нужно, а затем уходит и освобождает для следующего человека из очереди.


import {test} from "./tester";

/*
Задача: смоделировать очередь людей (queue) на сервер из slots видеокарт
*/

function predict(queue, slots) {
  // карты, установленные на сервере, на них мы будем влиять очередью
  const cards = Array(slots).fill(0);

  // пока в очереди есть необслуженные данные
  while (queue.length) {
    // обрабатываем их
    const current = queue.shift();
  }

  // а вернуть нам нужно минимальное время, через которое освободится хотя бы одна видеокарта
  return Math.min(...cards);
}

test(predict([1, 2, 3], 1), 6);
test(predict([1, 2, 3], 2), 2);
test(predict([1, 2, 3], 3), 1);
test(predict([3, 2, 3], 3), 2);

Шаг 3

Для этого напишем небольшую функцию, которая будет искать наименее занятую карту и станем складывать её текущую занятость с прогнозируемой занятостью от человека из очереди. Всё, наша простенькая симуляция готова!

import {test} from "./tester";

/*
Задача: смоделировать очередь людей (queue) на сервер из slots видеокарт
*/

function findMinIndex(machines) {
  const min = Math.min(...machines);

  return machines.indexOf(min);
}

function predict(queue, slots) {
  // карты, установленные на сервере, на них мы будем влиять очередью
  const cards = Array(slots).fill(0);

  // пока в очереди есть необслуженные данные
  while (queue.length) {
    // обрабатываем их
    const current = queue.shift();

    const minIndex = findMinIndex(cards);

    cards[minIndex] += current;
  }

  // а вернуть нам нужно минимальное время, через которое освободится хотя бы одна видеокарта
  return Math.min(...cards);
}

test(predict([1, 2, 3], 1), 6);
test(predict([1, 2, 3], 2), 2);
test(predict([1, 2, 3], 3), 1);
test(predict([3, 2, 3], 3), 2);
test(predict([4, 5, 3, 3], 2), 7);

File tester.js

const results = document.getElementById('results')

export function test(left, right) {
  const result = document.createElement('li');

  if (left === right) {
    result.innerHTML = "Тест пройден!";
    result.style.color = "green";
  } else {
    result.innerHTML = `Тест не пройден! ${left} не равно ${right}`;
    result.style.color = "red";
  }

  results.appendChild(result);
}