169 / 66 / 15
Регистрация: 24.03.2013
Сообщений: 467
Записей в блоге: 1

Адекватная критика выполнения задачи

09.12.2016, 21:44. Показов 938. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Недавно пришло тестовое задание от нашей крупной IT компании.

Задание звучало, так:

Кликните здесь для просмотра всего текста

Реализовать объект для учета однотипных событий в системе.

Например, отправка фото в сервисе фотографий.

События поступают в произвольный момент времени.

Возможно как 10К событий в секунду так и 2 в час.

Интерфейс:
  1. Учесть событие.
  2. Выдать число событий за последнюю минуту (60 секунд).
  3. Выдать число событий за последний час (60 минут).
  4. Выдать число событий за последние сутки (24 часа).



Ну соответственно моя реализация, состоящая из 3 сущностей:

1. EventCounter
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
package eventmanagment;
 
public interface EventCounter {
    void eventPerformed();
    long getEventCount(TimePeriod period);
}


2. TimePeriod
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
7
8
package eventmanagment;
 
public enum TimePeriod {
    LAST_SECOND,
    LAST_MINUTE,
    LAST_HOUR,
    LAST_DAY
}


3. EventCounterImpl
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package eventmanagment;
 
import java.util.HashMap;
import java.util.Map;
 
/***
 * Реализовать объект для учета однотипных событий в системе.
 *
 * Например, отправка фото в сервисе фотографий.
 * События поступают в произвольный момент времени.
 * Возможно как 10К событий в секунду так и 2 в час.
 * Интерфейс.
 *  1.  Учесть событие.
 *  2.  Выдать число событий за последнюю минуту (60 секунд).
 *  3.  Выдать число событий за последний час (60 минут).
 *  4.  Выдать число событий за последние сутки (24 часа).
 *
 * Общая идея:
 *  1. Счетчик событий строго дискретен, с дискретным шагом в 0.01 секунду
 *  2. Идентификационные сущности событий, счетчик не сохраняет.
 *  3. При создании счетчика создается:
 *      1. Map<Step, Count> - для хранения количества событий
 *      2. Long initialTimestamp - переменная "начало времен", от него вычисляются все последующие Step
 *  4. При наступлении события:
 *      1. Вычисляется его Step и его Count инкрементируется
 *      2. Если Step'a нет в Map, то он добавляется в map с Count = 1
 *  5. Алгоритм вычисления Step'a
 *      Зная, время, когда произошло событие, можно вычислить его Step
 *          Long initialTimestamp = this.initialTimestamp;
 *          Long eventTimestamp = System.currentTimeMillis();
 *          Long stepIndex = (eventTimestamp - initialTimestamp) / 10;
 *  6. Алгоритм подсчета количества событий
 *  6.1 Для TimePeriod LAST_SECOND
 *      Зная, точное время когда произошло обращение за количеством событий,
 *      можно вычислить step обращения. Далее, просуммировать все значения
 *      step, step - 1, step - 2, ... step - SECONDS / STEP_SIZE - это и будет
 *      ответом на результат
 *
 * Created by Almaz on 08.12.2016.
 */
public class EventCounterImpl implements EventCounter {
    public static final int STEP_SIZE = 10;
    public static final int SECOND_SIZE = 1000;
    public static final int MINUTE_SIZE = 60 * SECOND_SIZE;
    public static final int HOUR_SIZE = 60 * MINUTE_SIZE;
    public static final int DAY_SIZE = 24 * HOUR_SIZE;
 
    private final Long initialTimestamp;
    private volatile Map<Long, Integer> map;
 
    public EventCounterImpl(Long initialTimestamp) {
        this.initialTimestamp = initialTimestamp;
        map = new HashMap<>();
    }
 
    public void eventPerformed(){
        long currentTime = System.currentTimeMillis();
        Long step = getStep(currentTime);
 
        synchronized (map) {
            Integer value = map.get(step);
            if (value == null) {
                map.put(step, 1);
            } else {
                map.put(step, value + 1);
            }
        }
    }
 
    private Long getStep(long currentTime) {
        return (currentTime - initialTimestamp) / STEP_SIZE;
    }
 
    public long getEventCount(TimePeriod period) {
        long currentTimeMillis = System.currentTimeMillis();
        switch (period){
            case LAST_DAY: return lastDayEventCount(currentTimeMillis);
            case LAST_HOUR: return lastHourEventCount(currentTimeMillis);
            case LAST_MINUTE: return lastMinuteEventCount(currentTimeMillis);
            case LAST_SECOND: return lastSecondEventCount(currentTimeMillis);
 
            default: throw new IllegalArgumentException("Unknown time period " + period);
        }
    }
 
    private long eventCount(long step, int size){
        long result = 0;
 
        for (long i = step; i > step - size; i--) {
            Integer value = map.get(i);
            if(value != null)
                result+= value;
        }
 
        return result;
    }
 
    private long lastSecondEventCount(long currentTimeMillis) {
        int size = SECOND_SIZE / STEP_SIZE;
        return eventCount(getStep(currentTimeMillis), size);
    }
    private long lastMinuteEventCount(long currentTimeMillis) {
        int size = MINUTE_SIZE / STEP_SIZE;
        return eventCount(getStep(currentTimeMillis), size);
    }
    private long lastHourEventCount(long currentTimeMillis) {
        int size = HOUR_SIZE / STEP_SIZE;
        return eventCount(getStep(currentTimeMillis), size);
    }
    private long lastDayEventCount(long currentTimeMillis) {
        int size = DAY_SIZE / STEP_SIZE;
        return eventCount(getStep(currentTimeMillis), size);
    }
}




Ну и тесты собственно:

1. Simple tests
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package eventmanagment;
 
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
 
/**
 * Created by Almaz on 08.12.2016.
 */
public class EventCounterImplTest {
    private static final int MILLION = 1000000;
    private EventCounter eventCounter;
 
    @Before
    public void init(){
        eventCounter = new EventCounterImpl(System.currentTimeMillis());
    }
 
    @Test
    public void test1(){
        eventCounter.eventPerformed();
 
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_HOUR));
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_DAY));
    }
    @Test
    public void test2(){
        eventCounter.eventPerformed();
        eventCounter.eventPerformed();
        eventCounter.eventPerformed();
        eventCounter.eventPerformed();
 
        Assert.assertEquals(4L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(4L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
        Assert.assertEquals(4L, eventCounter.getEventCount(TimePeriod.LAST_HOUR));
        Assert.assertEquals(4L, eventCounter.getEventCount(TimePeriod.LAST_DAY));
 
        eventCounter.eventPerformed();
        Assert.assertEquals(5L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(5L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
        Assert.assertEquals(5L, eventCounter.getEventCount(TimePeriod.LAST_HOUR));
        Assert.assertEquals(5L, eventCounter.getEventCount(TimePeriod.LAST_DAY));
    }
 
    @Test
    public void test3() throws InterruptedException {
        eventCounter.eventPerformed();
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
 
        // sleep for 1 second
        Thread.sleep(1000);
        eventCounter.eventPerformed();
        Assert.assertEquals(1L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(2L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
 
        // sleep for 1 second
        Thread.sleep(1000);
        eventCounter.eventPerformed();
        eventCounter.eventPerformed();
        eventCounter.eventPerformed();
 
        Assert.assertEquals(3L, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
        Assert.assertEquals(5L, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
    }
 
    /***
     * Хм...
     * Может ли тут компилятор произвести некоторое количество оптимизаций,
     * инлайнинги и все такое умное, что этот тест вообще окажется не верным?
     */
    @Test
    public void test4() throws InterruptedException {
        handleMillionEvents();
        Thread.sleep(9 * EventCounterImpl.STEP_SIZE);
        Assert.assertEquals(MILLION, eventCounter.getEventCount(TimePeriod.LAST_SECOND));
    }
 
    private void handleMillionEvents() throws InterruptedException {
        for (int i = 0; i < MILLION; i++) {
            eventCounter.eventPerformed();
        }
    }
 
    @Test
    public void test5() throws InterruptedException {
        handleMillionEvents();
        Thread.sleep(9 * EventCounterImpl.STEP_SIZE);
        handleMillionEvents();
        Thread.sleep(9 * EventCounterImpl.STEP_SIZE);
        handleMillionEvents();
        Thread.sleep( EventCounterImpl.STEP_SIZE);
        Assert.assertEquals(3 * MILLION, eventCounter.getEventCount(TimePeriod.LAST_MINUTE));
    }
}


2. EventCounterImplParallelTest
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package eventmanagment;
 
import org.junit.Assert;
import org.junit.Test;
 
/**
 * Created by Almaz on 08.12.2016.
 */
public class EventCounterImplParallelTest {
    /***
     * Test case 1:
     *
     *  In this case 2 threads generated events
     *  First thread generate 10'000 events
     *  Second thread generate 100'000 events
     *
     *  Expected result: getEventCount(LAST_SECOND) return 110'000
     */
    @Test
    public void test1() throws InterruptedException {
        EventCounter counter = new EventCounterImpl(System.currentTimeMillis());
 
        Thread th1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter.eventPerformed();
            }
        });
 
 
        Thread th2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                counter.eventPerformed();
            }
        });
 
        th1.start();
        th2.start();
 
        th1.join();
        th2.join();
 
        Assert.assertEquals(110000L, counter.getEventCount(TimePeriod.LAST_SECOND));
    }
 
    /***
     * Test case 1:
     *
     *  In this case 2 threads generated events
     *  First thread generate 10'000 events and sleep for 1 second
     *  Second thread generate 100'000 events and sleep for 1 second
     *
     *  Expected result: getEventCount(LAST_SECOND) return 110'000
     */
    @Test
    public void test2() throws InterruptedException {
        EventCounter counter = new EventCounterImpl(System.currentTimeMillis());
 
        Thread th1 = new Thread(() -> {
            try {
                for (int i = 0; i < 10000; i++) {
                    counter.eventPerformed();
                }
 
                Thread.sleep(10 * EventCounterImpl.STEP_SIZE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
 
 
        Thread th2 = new Thread(() -> {
            try {
                Thread.sleep(5 * EventCounterImpl.STEP_SIZE);
                for (int i = 0; i < 100000; i++) {
                    counter.eventPerformed();
                }
                Thread.sleep(3 * EventCounterImpl.STEP_SIZE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
 
        th1.start();
        th2.start();
 
        th1.join();
        th2.join();
 
        Assert.assertEquals(110000L, counter.getEventCount(TimePeriod.LAST_SECOND));
    }
}


Проект на GitHub

Может, кто подскажет, что и где в этом коде непорядок.

Заранее благодарен, за конструктивный ответ
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
09.12.2016, 21:44
Ответы с готовыми решениями:

Индикатор выполнения задачи
Можно ли каким-нибудь способом в Фортране сделать индикатор выполнения задачи?

Задачи для выполнения
1. Вывести в окно браузера четные числа в диапазоне от 0 до 20 (используя цикл!). 2. Создать HTML-форму, позволяющую пользователю ввести...

математический ход выполнения задачи
6. Определите, что будет напечатано в результате работы следующего фрагмента программы: var k, s: integer; begin s:=0; k:=0; ...

3
Эксперт Java
 Аватар для KEKCoGEN
2399 / 2224 / 565
Регистрация: 28.12.2010
Сообщений: 8,672
10.12.2016, 00:21
Almaz_1993, непорядок в архитектуре. Вы изобрели какой то совершенно ненужный велосипед. Надо всего лишь сохранять событие и его timestamp а затем по запросу делать соотв. Выборку. Вы же нагородили кучу непонятного кода, ввели какое то понятие степ.
Синхронизацию зачем то сами делаете вместо того чтобы использовать соотв. коллекцию.
1
169 / 66 / 15
Регистрация: 24.03.2013
Сообщений: 467
Записей в блоге: 1
10.12.2016, 02:39  [ТС]
KEKCoGEN, А как тогда?

Просто List<Long> events?

Не по теме:

Хм... почему, я отмел идею с массивом Long?

0
Эксперт Java
 Аватар для KEKCoGEN
2399 / 2224 / 565
Регистрация: 28.12.2010
Сообщений: 8,672
10.12.2016, 10:49
Almaz_1993, да. Просто массива достаточно. В данном случае больше подойдёт LinkedList
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.12.2016, 10:49
Помогаю со студенческими работами здесь

Метод для выполнения задачи
Доброго времени! Помогите с решением! Задача: Есть 10 рулонов билетов по 100000 штук в каждом (000000-099999, …, 900000-999999),...

Как отсортировать после выполнения задачи
$rowlose = (&quot;SELECT * FROM `Stats` WHERE Wins ORDER BY Wins DESC LIMIT 10 &quot;); $ra = mysql_query($rowlose) or die(mysql_error()); $sa =...

Нахождение способов выполнения технической задачи
Доброго времени суток, форумчане! Я начинающий программист-самоучка. К моему несчастью, начал с Visual Basic.Net. Недавно все-таки нашел...

Закрывается окно после выполнения задачи
Короче, когда программа подходит до элемента вычисления то окно автоматом закрывается. Как отключить?

[решено]Останов выполнения задачи в RTOS
доброго времени суток! сейчас я на отладчной плате гоняю мегу32 с RTOS взятой из статьи (точнее из примера) ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

Новые блоги и статьи
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru