Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/4: Рейтинг темы: голосов - 4, средняя оценка - 4.50
169 / 66 / 15
Регистрация: 24.03.2013
Сообщений: 467
Записей в блоге: 1

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

09.12.2016, 21:44. Показов 930. Ответов 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
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
Установка Emscripten SDK (emsdk) и CMake на Windows для сборки C и C++ приложений в WebAssembly (Wasm)
8Observer8 30.01.2026
Чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. Система контроля версиями Git. . .
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru