Я занимаюсь имитацией банка, в котором у меня есть одна очередь и три кассира; целью является получение статистики, например, среднее время ожидания клиентов. У каждого кассира разное внимание, и каждый клиент приходит в банк каждые 1,5 минуты. У банка всего 5 часов. Теперь, есть ли способ, которым я мог бы программировать его в реальном времени (потому что я думаю, что это единственный способ), а затем каким-то образом ускорить jvm, чтобы быстрее получить статистику?Fast-foward в реальном времени java-моделирование
ответ
Вы не можете ускорить перемотку JVM, но вы можете запрограммировать это, чтобы имитировать в режиме реального времени, чтобы получить статистику в ближайшее время. Играйте с переменными, которые представляют время в достаточно малой единице времени (например, в секундах) и обычно выполняют симуляцию, увеличивая время в одном устройстве. Для очереди вы можете использовать деку, содержащую моменты, когда каждый клиент входит в банк, а затем повторяется со временем.
private static int TOTAL_TIME = 5*3600; // Hours to seconds
private static int TIME_BETWEEN_CLIENTS = 90; // In seconds
private static int CASHIERS = 3;
public static void main(String[] args) {
// Create cashiers and assign range of attentions time to each cashier, in seconds
// This is an example for cashiers with 3, 3~6 and 4.5~15 minutes
List<Cashier> cashiers = new ArrayList<Cashier>(CASHIERS);
cashiers.add(new Cashier(180, 180));
cashiers.add(new Cashier(180, 360));
cashiers.add(new Cashier(270, 900));
int time = 0; // Counting variable in seconds
int waitingTime = 0; // Save here all waiting time for all clients
int clients = 0; // Save here all clients
// Register here all available cashiers
ArrayList<Cashier> freeCashiers;
Deque<Integer> queue = new ArrayDeque<Integer>(); // Clients queue
// Iterate until bank closes and all clients have been attended
while (time < TOTAL_TIME || !queue.isEmpty()) {
// New client if the bank is not closed
if (time < TOTAL_TIME && time%TIME_BETWEEN_CLIENTS == 0) {
queue.add(time); // Register customer start waiting time
clients++;
}
// Check for free cashiers when someone is on queue
if (!queue.isEmpty()) {
freeCashiers = new ArrayList<Cashier>(CASHIERS);
for (Cashier c : cashiers) {
if (c.isFree(time))
freeCashiers.add(c);
}
if (!freeCashiers.isEmpty()) {
// Register spent time for the removed client
waitingTime += time - queue.removeFirst();
// Select a random cashier from all the available cashiers
Cashier randomAvailableCashier = freeCashiers.get(Cashier.RANDOM.nextInt(freeCashiers.size()));
// Register when the randomly selected cashier will be free again
randomAvailableCashier.attendNewClient(time);
}
}
time++; // Adds one second
}
// Calculate statistics
int avgWaitingTime = waitingTime/clients; // In seconds
System.out.println("Average waiting time on queue: " + formatTime(avgWaitingTime));
}
/**
* Formats a time in minutes and seconds
* @param time the time in seconds
* @return the formatted time
*/
private static String formatTime(int time) {
StringBuilder result = new StringBuilder();
if (time > 60) {
result.append(time/60).append(" minutes");
time %= 60;
if (time > 0)
result.append(" and ");
else
result.append(".");
}
if (time > 0)
result.append(time).append(" seconds.");
return result.toString();
}
И класс Кассира:
public class Cashier {
public static final Random RANDOM = new Random();
private int minAttentionTime, maxAttentionTime, endTime;
/**
* Constructs new Cashier with a range of possible attention time, in seconds
* @param minAttentionTime in seconds
* @param maxAttentionTime in seconds
*/
public Cashier(int minAttentionTime, int maxAttentionTime) {
this.minAttentionTime = minAttentionTime;
this.maxAttentionTime = maxAttentionTime;
endTime = 0;
}
/**
* Register end time with a random attention time in the range.
* @param currentTime the current time in seconds
*/
public void attendNewClient(int currentTime) {
endTime = currentTime + getRandomNumberInRange(minAttentionTime, maxAttentionTime);
}
/**
* Returns if this cashier is available
* @param currentTime the current time in seconds
* @return true if this cashier is free, false otherwise
*/
public boolean isFree(int currentTime) {
return currentTime >= endTime;
}
/**
* Returns a random number in range [min, max]
* @param min the minimum number, inclusive
* @param max the maximum number, inclusive
* @return a random number in range [min, max]
*/
private int getRandomNumberInRange(int min, int max) {
return RANDOM.nextInt(max - min + 1) + min;
}
public String toString() {
return String.valueOf(endTime);
}
}
С этой реализацией новым клиент будет идти к случайному свободному кассиру.
А что, если у каждого кассира есть такая же возможность выбора? Должно ли генерироваться случайное число, разделенное на три, а затем проверенное значение для выбора? – niklabaz
Нет, если вы разделите случайное число, вы получите доступ к позиции за пределами. Вы можете создать случайное число в диапазоне с Random nextInt (arrayLenght), но вы должны проверить все позиции, так что лучший способ - изменить массив для списка и сделать Collections.shuffle (cashiersEndTime) для рандомизации позиций до итерации а затем проверить с первой позиции, как на самом деле. –
Это не работает для небольших времен ожидания, Im пытается с кассиром ОДИН, время ожидания от 0,5 до 1,5 минут, кассир ДВА от 0,5 до 2 минут, а cahsier THREE от 0,5 до 2,5 минут. Также с клиентами, произвольно выбирающими, если есть более одного бесплатного кассира. – niklabaz
Если вы использовали систему очередей, вы могли бы пойти очень быстро. Очередь будет содержать события, которые идут вверх, и временную метку, когда они подлежат. Очередь будет организована по метке события. Первоначально вы могли засеять эту очередь новым клиентом каждые 1,5 минуты, а событие для закрытия банка через 5 часов. Затем вы вытаскиваете первое событие из очереди, выясняете, что это вызывает. Например, первое событие ввода клиента заставляет вас увеличить счет очереди ожидания клиента. Кассир, становящийся свободным, вызывает подсчет очереди ожидания и активность агента-клиента, которая длится для некоторой случайной длины времени. Это приводит к тому, что в очередь помещается новое событие (другое приглашение). Когда кассир свободен, и нет клиентов в очереди, вы устанавливаете пустой флажок кассира, который будет проверяться, когда вы будете обрабатывать событие ввода клиента. Вы можете быстро проработать весь день в течение нескольких секунд с подходом, и вы можете собирать статистику о том, что вы хотите на каждом мероприятии.
Я не могу посеять очередь, а затем вводить другие события между ними. Я просто мог бы занять место за закрытием банковского события, не так ли? – niklabaz
С объектом очереди акций, правильно, но вы можете легко написать свои собственные функции очереди, которые работают со стандартным списком объектов событий. Затем ваш метод push может вставить новое событие в метку времени или событие. –
Если вы не против использовать формулы, здесь моя математика. Если у какого-то кассира есть время T1 для обработки одного человека, то этот кассир обрабатывает 1/T1 человек за единицу времени. Количество людей, обработанных кассирами N, добавляется. Возвращаясь от скорости обработки на время обработки мы получаем общее время для обработки одного человека всех кассиров:
Tcom = 1/(1/T1 + 1/T2 + ... + 1/Tn)
Вы сравните это время с 1,5 минут, а если TCOM < = 1,5 минуты, то ваша очередь будет в основном пуста или состоят из 1 человека (а среднее время ожидания будет около половины среднего значения Ti). В случае Tcom> 1,5 минуты ваша очередь будет постоянно расти на одного человека, каждый Tcom - 1,5 минуты. Длина очереди в конце рабочего дня будет Lavg = 5 * 60/(Tcom - 15) человек (и половина из них в среднем). Каждый человек в голове очереди удаляется из него каждые минуты Tcom. Это означает, что среднее время ожидания будет Tcom * Lavg/2
.
Я знаю, что это очень приблизительные оценки, но почему бы и нет?
(Вы удалили другой почти такой же вопрос. Вот длинный ответ я уже писал, зная, что. Хорошо, что вы имели эту копию, так что я не тратить мое время)
Вот функционал псевдо. Я действительно закодировал это, из любопытства.
Я использую компьютерный язык под названием APL, который, скорее всего, неизвестен вам, следовательно, псевдо.
Вам необходимо создать двумерную таблицу, т.е. массив с шестью столбцами. Если вы не можете создавать двумерные массивы, вы можете альтернативно (надеюсь) создать одномерные массивы, т.е. списки, в которых один список содержит значения одного столбца в таблице. Важно то, что вы можете индексировать в массивы. Если вы используете listst, вы должны немного расширить код.
Вы будете работать только с целыми значениями.
Решение состоит в том, что вы предварительно создали таблицу, в которой время прибытия клиента в столбце 1. Все остальные столбцы содержат нули для начала. Затем вы просматриваете таблицу, обновляя другие столбцы, по очереди, используя вспомогательную переменную для кассиров.
После того, как вы зациклились на всех строках таблицы, вы извлекаете из него желаемые результаты, путем дополнительных вычислений.
Для действий кассиров вам нужна еще одна двумерная таблица, держащая [nr кассиров] строки и 3 столбца. Аналогично, вы можете заменить его на 3 списка, по одному на столбец таблицы. Столбцы 2 и 3 в этом маленьком столике накапливают каждого кассира, потраченного на обслуживание клиента, и время, которое они провели в ожидании клиентов.
Вы не работаете с часами, но с секундами с начала дня. Например, 8am равно 28800 (т.е. количество секунд, прошедших с начала дня). К этому значению вы можете легко добавить время прибытия клиента с шагом в 90 секунд (или любое, произвольное количество секундных интервалов). Вы заранее создаете время прибытия клиента для всего 5-часового (или любого часа) дня.
// Create a table with 6 columns. Columns are
// 1: Customer arrival timestamp (first value is 28800) [seconds since midnight]
// 2: The timestamp the customer was attended [seconds since midnight]
// 3: The time a customer had to wait [seconds]
// 4: The time the customer spent with the cashier [seconds]
// 5: The timestamp the customer leaves the bank [seconds since midnight]
// 6: The cashier # that provided service, 1,2 or 3 in your case
//
// If the customer arrive at regular 90 s intervals, the table now looks like this
// (10 first rows only, but you must populate it up to bank closing time)
// which would need ca 200 rows. Call this table "Cust":
// 28800 0 0 0 0 0
// 28890 0 0 0 0 0
// 28980 0 0 0 0 0
// 29070 0 0 0 0 0
// 29160 0 0 0 0 0
// 29250 0 0 0 0 0
// 29340 0 0 0 0 0
// 29430 0 0 0 0 0
// 29520 0 0 0 0 0
// 29610 0 0 0 0 0
//
// Create a variable for the cashiers, 1 row per cashier. Columns are:
// 1. An "action timestamp", initially 28800 [seconds since midnight]
// 2. Accumulation of cashiers attention time [seconds]
// 3. Accumulation of cashiers wait/slack time [seconds]
//
// The table now looks like this
// (add more rows if you have more cashiers). Call this table "Cash":
// 28800 0 0
// 28800 0 0
// 28800 0 0
rows = [numers of rows in Cust]
i = 0
:While i < rows
// Note! This pseudocode uses 0-origin, ie. array[0] is the first element
// Find the row number of Cash with the _smallest_ value in it's column 1
row = [0, 1 or 2] // You commonly first find the smallest number, then compare it against each row. The match is the row with smallest number.
// Attention time for this customer (you said "range of"),
// we use 265 s now, for simplicity, but you can give time another value each time
time = 265
:If Cust[i;0]<Cash[row;0] // Customer has waited
Cust[i;1]=Cash[row;0] // Timestamp this Customer got service
Cust[i;3]=time // Time spent with cashier
Cust[i;4]=Cash[row;0]+time // Timestamp customer leaves the bank
Cust[i;5]=row // Which cashier provided the service
Cash[row;1]+=time // Increase accumulated attend time for cashier
Cash[row;0]+=time // Next timestamp this cashier is free
:Else // Cashier had free time (bank was empty until now)
Cash[row;2]+=Cust[i;0]-Cash[row;0] // Accumulate freetime for cashier
Cash[row;1]+=time // Accumulate attend time for cashier
Cust[i;1]=Cust[i;0] // There was no wait time for customer
Cust[i;3]=time // Time spent with cashier
Cust[i;4]=Cust[i;0]+time // Timestamp customer leaves the bank
Cust[i;5]=row // Which cashier provided the service
Cash[row;0]=Cust[i;0]+time // Next timestamp this cashier is free
:End
i+←1
:End
// Resolve customer wait times, equals [time attended] - [time arrived] and
// populate 3rd column of Cust (you must probably loop), row by row
Cust[n;2] = Cust[n;1] - Cust[n;0] // n = each row
// Cust now looks like this:
// 28800 28800 0 265 29065 0
// 28890 28890 0 265 29155 1
// 28980 28980 0 265 29245 2
// 29070 29070 0 265 29335 0
// 29160 29160 0 265 29425 1
// 29250 29250 0 265 29515 2
// 29340 29340 0 265 29605 0
// 29430 29430 0 265 29695 1
// 29520 29520 0 265 29785 2
// 29610 29610 0 265 29875 0
fnAvg = [function that calculates the average of a list of numbers]
// Extract the results
// Note: For example "Cust[;2]" means _all rows in column 2 of Cust_, ie. a list of numbers
// You don't need to create any lists though, just loop through them all and calculate/accumulate
'Nr of customers attended immediately: ',[number of zeroes in Cust[;2]]
'Nr of customers who waited: ',[number of non-zeroes in Cust[;2]]
'Wait times: ',[all numbers in Cust[;2] - this is a list of numbers]
'Average wait times: ',[avg Cust[;2]]
'Average wait times (only those who waited): ',[avg Cust[;2] elements that are non-zero]
'Total cashier attend times: ',Cash[;1]
'Total cashier free times: ',Cash[;2]
// And finally a verification calc (backwards calc, just for curiosity)
'Check: Total customer existance time: ',Cust[i-1;4]-Cust[0;0]
'Check: Cashier total times (should be close to above value): ',[sum of Cash[n;1 2]]
В результате с указанными выше аргументами (числа не секунды, если иное сказана):
Nr of customers attended immediately: 10
Nr of customers who waited: 0
Wait times: 0 0 0 0 0 0 0 0 0 0
Average wait times: 0
Average wait times (only those who waited): 0
Total cashier attend times: 1060 795 795
Total cashier free times: 15 100 190
Check: Total customer existance time: 1075
Check: Cashier total times (should be close to previous row): 1075 895 985
Если у вас есть 20 клиентов, прибывающие и использовать случайные времена ПРИСУТСТВУЙТЕ между 100 и 480 секундами, вы можете получить, например:
Nr of customers served immediately: 8
Nr of customers waited: 12
Wait times: 0 0 0 0 0 14 0 0 0 200 120 147 183 122 149 111 185 178 244 218
Average wait times: 93.55
Average wait times (only those who waited): 155.9166667
Total cashier attend times: 1820 1836 1819
Total cashier free times: 217 197 309
Check: Total customer existance time: 2128
Check: Cashier total times (should be close to previous row): 2037 2033 2128
with Cust (edited: was erratically Cash) table looking like this:
28800 28800 0 160 28960 0
28890 28890 0 433 29323 1
28980 28980 0 114 29094 2
29070 29070 0 194 29264 0
29160 29160 0 117 29277 2
29250 29264 14 149 29413 0
29340 29340 0 470 29810 2
29430 29430 0 390 29820 1
29520 29520 0 417 29937 0
29610 29810 200 253 30063 2
29700 29820 120 389 30209 1
29790 29937 147 155 30092 0
29880 30063 183 445 30508 2
29970 30092 122 169 30261 0
30060 30209 149 216 30425 1
30150 30261 111 403 30664 0
30240 30425 185 408 30833 1
30330 30508 178 220 30728 2
30420 30664 244 173 30837 0
30510 30728 218 200 30928 2
Попробуйте с наполнением 1-й столбца Каст с другой, более случайным клиентом arrivbal раз, и для каждой итерации, время со значениями, которые соответствуют вашему реальная окружающая среда лучше.
Это псевдо поддерживает как «банк временно пуст», так и «длинный que all time», а также поддерживает «Как только банк закрывается через 5 часов, каждый клиент получает» -критерий (оставшиеся клиенты будут очищены »,).
Удачи! :-)
- 1. Изменения в реальном времени в реальном времени
- 2. Обновление в реальном времени в реальном времени
- 3. Получайте обновления в реальном времени в реальном времени в Kafka
- 4. Обработка звука в реальном времени в реальном времени
- 5. Игра в реальном времени Django в реальном времени
- 6. Соберите данные в реальном времени в реальном времени facebook
- 7. Обновление в реальном времени GWT CEll в реальном времени
- 8. Обновления в реальном времени в реальном времени с сервера
- 9. Обмен сообщениями в реальном времени в реальном времени
- 10. Фильтрация видео в реальном времени в реальном времени
- 11. не в реальном времени/не в реальном времени сортировка JTable
- 12. Компиляция в реальном времени?
- 13. Подписки в реальном времени
- 14. В реальном времени Понимание
- 15. местоположение в реальном времени
- 16. Статистика в реальном времени?
- 17. oracle в реальном времени
- 18. Расчет в реальном времени?
- 19. Синхронизация в реальном времени
- 20. Диаграмма в реальном времени
- 21. Нажатие в реальном времени
- 22. Обновления в реальном времени
- 23. Обновление в реальном времени
- 24. таймер времени в python в реальном времени
- 25. Режимы реального времени в реальном времени
- 26. индексирование реального времени в реальном времени
- 27. График реального времени в реальном времени
- 28. Исправление в реальном времени IMFMediaSource метки времени
- 29. Архитектура потокового рабочего времени в реальном времени
- 30. Приложение для отслеживания времени в реальном времени
Я уверен, что это просто как раз, когда математика уравнение придет в ... Не «быстрая перемотка вперед» виртуальная машина ... что в техническом плане нет .. вы не может – 3kings
Теперь я могу полностью упустить эту метку, но вы должны разработать концепцию «тика», в которой один тик = единица времени irl. Чтобы ускорить или замедлить время в симуляции, вы просто увеличиваете количество тиков в секунду. –
«в реальном времени» противоречит «быстрой перемотке», но если у вас есть симуляция, тогда у вас есть концепция периодов времени, которые вы просто разделите. Например, деление на 2 приведет к тому, что симуляция будет идти в два раза быстрее. –