powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
140 сообщений из 140, показаны все 6 страниц
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514248
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сразу хочу сказать, что никого оскорблять не хочу и меня интересует только техническая сторона вопроса. Выкладываю в паблик текст задания после того как мне отказались ответить на мои уточняющие вопросы по поводу того, что именно не так.

Задачу стояла так:

авторОчередь заданий с относительным порядком

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


Пример: если значение ключа - это номер счёта в банке, а задание - операция со счётом, то операции над одним и тем же счётом должны выполняться последовательно и в правильном порядке, при этом операции над разными счетами могут выполняться параллельно для увеличения общей производительности.

Пример: подход, при котором очередь выполняет все задания последовательно в единственном потоке, удовлетворяет условию на порядок выполнения заданий с одинаковым значением ключа.


Примерный интерфейс задания:
interface Task implements Runnable {
String getKey();
}

Примерный интерфейс очереди:
interface TaskExecutor {
void submit(Task task);
}



Решение должно использовать только стандартную библиотеку Java 8, плюс тестовые фреймвоки на выбор.

Решение должно использовать более одного потока для выполнения заданий.
Решение должно контроллировать (ограничивать) максимальное количество используемых потоков.

Не требуется делать решение, покрывающее все возможные варианты, учтённые или не учтённые в описании выше.

Мы ожидаем, что решение займет несколько часов.
Если есть сомнения, делайте как проще и задокументируйте, какие упрощения или предположения вы сделали.

Давайте тесты обсуждать не будем, только экзекутор.

я решил задачу двумя способами. Первый - очень очевидно и просто, но с неточностью(не учёл, что hashCode может быть отрицательным), но не достаточно производительно.

Хотел бы обсудить второй способ. Лично мне он очень понравился и я был удовлетворён, что смог решить.

вот код:

Код: 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.
public class ThreadPoolImpl implements ThreadPool {
    private final ConcurrentMap<String, CompletableFuture<Void>> taskMap = new ConcurrentHashMap<>();
    private volatile boolean isStopped = false;
    private final ThreadPoolExecutor poolExecutor;

    public ThreadPoolImpl(int threadCount) {
        poolExecutor = new ThreadPoolExecutor(threadCount, threadCount, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
    }

    @Override
    public void execute(MyTask myTask) {
        if (isStopped) {
            throw new IllegalStateException("Pool already terminated");
        }
        final String key = myTask.getKey();
        taskMap.compute(key, (k, queue) -> {
            CompletableFuture<Void> future = (queue == null)
                    ? CompletableFuture.runAsync(myTask, poolExecutor)
                    : queue.whenCompleteAsync((r, e) -> myTask.run(), poolExecutor);
            //to prevent OutOfMemoryError in case if we will have too much keys
            future.whenComplete((r, e) -> taskMap.remove(key, future));
            return future;
        });
    }


    @Override
    public void stop() {
        isStopped = true;
    }
}



а вот комментарий от проверяющего(Кстати спасибо ему большое, что он его выдал - всё таки я потратил время, выполнял задачу, услышать фидбэк очень интересно):

автор## Второй вариант решения

Преимущество этого подхода в том, что задачи с разными ключами будут занимать все доступные потоки.

Проблема предложенной реализации в том, что при использовании метода ConcurrentMap.compute функция ремапинга может быть вызвана несколько раз.
Если несколько потоков одновременно добавляют новые задания с одним и тем же ключом, некоторые из заданий будут многократно добавлены в цепочку CompletableFuture.

Простейший пример - какое-то задание T0 с ключом Х находится в обработке, то есть в мапе присутствует CompletableFuture F0.
Два разных потока одновременно добавляют новые задания T1 и Т2 с тем же ключом Х. В обоих потоках вычисляется taskMap.compute от F0, внутри функции ремапинга оба потока добавляют свои задания в цепочку на F0, но только одному потоку удаётся завершить taskMap.compute, например первому потоку, который создаст CompletableFuture F1. Второй поток вычисляет ремапинг ещё раз, на этот раз от F1, и добавляет своё задание в цепочку поверх F1.

В итоге, если в poolExecutor достаточно свободных потоков, после завершения T0 оба задания T1 и Т2 начнут выполняться одновременно, а после завершения Т1 запуститься ещё один экземпляр Т2.

Дальше я задал следующий вопрос:

По первому решению я согласен с комментариями, а вот что касается второго - хотелось бы уточнений.

авторВ jdk ConcurrentHashMap compute не может исполняться Параллельно для ключей из одного бакета. То есть потоки с задачами T1 и T2 выстроятся в очередь и не будет описанных выше проблем.
/**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
* mapping). The entire method invocation is performed atomically.
* Some attempted update operations on this map by other threads
* may be blocked while computation is in progress, so the
* computation should be short and simple, and must not attempt to
* update any other mappings of this Map.
*/
Это довольно легко проверить если сделать Thread.sleep внутри compute и сделать из разных потоков put с одинаковыми ключами.
Я полагаю, что проблема в том, что я использовал ConcurrentHashMap через интерфейс ConcurrentMap, документацию которого я не прочитал. ConcurrentMap интерфейс действительно разрешает несколько раз выполнять compute(видимо для CAS алгоритмов)
/*The default implementation may retry these steps when multiple
* threads attempt updates including potentially calling the remapping
* function multiple times.
*/
И тогда я понимаю как может произойти описанная ситуация.

Мои мысли правильны?

Но на это сообщение мне ответили, что коллеги не имеют достаточно свободного времени, чтобы мне отвечать.

Я полагаю, что неправильное решение значит решение не такое какое они считают наиболее правильным.

Вот и хотелось бы обсудить как ещё можно было бы решить такую задачу. Как по мне с точки зрения производительности и распределения задач особо ничего уже не улучшить. Можно только играться с экзекутором, который в конструкторе создаётся. В идеале его просто передавать туда аргументом, но это мелочь на мой взгляд для такого задания
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514249
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторПо первому решению я согласен с комментариями, а вот что касается второго - хотелось бы уточнений.

это часть письма была, конечно.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514262
irbis_al
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Я в толк не возьму,а Вы тестировали...или просто сделали...Когда речь идёт о многопоточном,то там надо эмулировать ситуации...
В Вашем случае должна быть эмуляция и быть бы лог эмуляции
Типа
Начинает исполнятся задача такая-то(с ключом)
Исполняется задача такая-то
Исполнилась задача такая-то
Начинает исполнятся задача такая-то(с ключом)
Исполняется задача такая-то
Начинает исполнятся задача такая-то(с ключом)
Исполнилась задача такая-то
Исполняется задача такая-то
Начинает исполнятся задача такая-то(с ключом) Опаньки...а уже этот ключ не закончил выполнение
поэтому wait

В частности в эмуляцию подаём все с одинаковыми ключами и я в логе должен видеть однозначно последовательное выполнение.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514264
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
irbis_alquestioner,

Я в толк не возьму,а Вы тестировали...или просто сделали...Когда речь идёт о многопоточном,то там надо эмулировать ситуации...
В Вашем случае должна быть эмуляция и быть бы лог эмуляции
Типа
Начинает исполнятся задача такая-то(с ключом)
Исполняется задача такая-то
Исполнилась задача такая-то
Начинает исполнятся задача такая-то(с ключом)
Исполняется задача такая-то
Начинает исполнятся задача такая-то(с ключом)
Исполнилась задача такая-то
Исполняется задача такая-то
Начинает исполнятся задача такая-то(с ключом) Опаньки...а уже этот ключ не закончил выполнение
поэтому wait

В частности в эмуляцию подаём все с одинаковыми ключами и я в логе должен видеть однозначно последовательное выполнение.

Для себя на этапе разработки делал, но потом написал тест, который делает это "более умно". Но это совсем другая история. Предлагаю в данном топике тесты не обсуждать.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514267
irbis_al
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Тут не в обсуждении тестов дело...
Как говорил Винни Пух ,-Мёд он либо есть либо его нет.
Если не существует тестового набора при котором задачи с одним ключом выполняются одновременно,то
Вы всё правильно сделали...иначе неправильно.
Тут в комментариях Вашего визави было сказано,что такая ситуация произойти может.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514269
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я в коде навскидку вижу одну проблему: рекурсивные фьючи, и как следствие глубокий стек вызовов при большом количестве достаточно часто поступающих задач с одинаковым ключом, с возможностью переполнения (stackoverflowerror).

То что у них нет времени на дискуссии - это конечно огонь) засцали небось
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514275
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
irbis_al,

Безусловно, такие тесты есть, у меня тоже вызвало вопросы, что тест не валился, а они говорят, что такое может быть. Но это ж конечно многопоточка, если ты не получил ни разу - не значит, что все верно
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514286
irbis_al
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerirbis_al,

Безусловно, такие тесты есть, у меня тоже вызвало вопросы, что тест не валился, а они говорят, что такое может быть. Но это ж конечно многопоточка, если ты не получил ни разу - не значит, что все верно

В том то и дело ,что задание на многопоточность это айсберг...Вершина видная это код ,что Вы написали,а остальное инфраструктура(тесты и логи) где Вы доказываете,что Вы не верблюд и конфликтной ситуации произойти не может.
Я обычно эмулирую с семафорным захватом.Если произошло поточное конфликтное столкновение то эти потоки висят(сцепились как два терьера)...ждут когда кто-то семафоры отпустит.
От Вас наверное именно этого (Невидимой части айсберга) и ожидали.
А раз Вы не серьёзно отнеслись к этой подводной части с Вами никто и разговаривать не захотел.(несмотря на то,что возможно у Вас всё работает верно,-Во всяком случае написано довольно изящно)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514315
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
irbis_alquestionerirbis_al,

Безусловно, такие тесты есть, у меня тоже вызвало вопросы, что тест не валился, а они говорят, что такое может быть. Но это ж конечно многопоточка, если ты не получил ни разу - не значит, что все верно

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

Раз уж зашёл разговор про тесты...я в начале таски пробовал добавлять в сет(потокобезопасный) ключ, в конце - удалял. Если в начале не получалось добавлять - значит случилось что-то, что не должно было случиться и я этот факт регистрировал, в конце теста смотрел сколько инцидентов случилось. Тест сабмитил 100_000 тасков по 10 ключам, то есть по 10_000 на каждый ключ. Внутри каждой таски Thread.sleep длительностью от 5 до 30 мс. случайно.

А про семафор я чего-то не понял. Кто с кем сцепиться должен был и по какой причине? семафор же позволяет n потокам войти в критическую секцию.

Но дело явно не в тестах - они ведь явно написали, что код не потоко безопасный, содержит race condition-ы
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514359
ivanra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Странно выглядит придирка к default методу в интерфейса, без учета, какая использована реализация.
Приватная переменная, ни в каких сигнатурах не участвует. Можно было вообще её как Map объявить, так как все используемые методы - оттуда.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514385
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Я думаю, вас подвело знание английского:

авторSome attempted update operations on this map by other threads
* may be blocked

may - это не should/must/will

Я бы вообще сделал на synchronized - разница все равно видна только для очень высокого contention и даже там нужно тестировать, какой вариант лучше.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514396
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
scf,

Ну мы же все понимаем, что "может" случается для конкурентной модификации в рамках бакета.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514708
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerМы ожидаем, что решение займет несколько часов.


сли останется время, большим плюсом будет написание своей ОС, компилятора Java и аналога Варкрафта.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514723
vimba
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Я детально не вчитывался, но напервый взгляд нигде не сказано, что удалять из мапы нельзя находясь внутри compute, однако по факту это так, по крайней мере для openjdk 1.8.111. Вот этот кода кусок намертво виснет, ровно по той же причине по которой у меня повис и ваш экзекьютор:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
public static void main(String[] args) {
        ConcurrentHashMap map = new ConcurrentHashMap();
        map.compute(1, (o, o2) -> {
            map.remove(1);
            return 42;
        });

    }



В вашем коде действительно как и сказали проверяющие, есть ещё и возможность паралельного выполнения тасок по одному и тому же ключу, только причины другие, не те которые Вам отписали. Но прежде чем я вам их назову, сначала исключите зависание, вызванное тем что whenComplete может вызваться внутри compute, из-за того что фьюча уже закомплечена. Именно расстановка слипов вас и сгубила при тестировании.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514883
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimbaquestioner,

Я детально не вчитывался, но напервый взгляд нигде не сказано, что удалять из мапы нельзя находясь внутри compute, однако по факту это так, по крайней мере для openjdk 1.8.111. Вот этот кода кусок намертво виснет, ровно по той же причине по которой у меня повис и ваш экзекьютор:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
public static void main(String[] args) {
        ConcurrentHashMap map = new ConcurrentHashMap();
        map.compute(1, (o, o2) -> {
            map.remove(1);
            return 42;
        });

    }



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

А вас не смущает, что я тесты запускал и они проходили? Как это связано со слипами не понятно
Если Вы внимательно посмотрите, что remove выполняется не в compute треде

авторвас и сгубила при тестировании

Зачем пытаться, что-то придумывать если люди явно текстом написали, что их смущает?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514888
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerМы ожидаем, что решение займет несколько часов.


сли останется время, большим плюсом будет написание своей ОС, компилятора Java и аналога Варкрафта.

Да, я в эти оценки тоже не верю. Год наверное назад был в одной конторе на собеседовании, поотвечал на вопросы, потом меня начинают спрашивать готов ли я сделать тестовое задание. А тогда у меня свободного времени особо не было и я скептически начал спрашивать что примерно за задание, какой объём. Мне говорят мол задачка небольшая часа на 3(на дом, естественно). В итоге я сказал, что мне лень её делать(текста я не получал). Потом спрашиваю знакомого из этой фирмы что за задание они дают и на сколько большое. В итоге выяснилось, что тот человек, который меня собеседовал с опытом 15+ лет буквально за полгода до моего собеседования пришёл в компанию и решал эту задачу. У него ушло 3 дня!
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514889
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerА вас не смущает, что я тесты запускал и они проходили? Как это связано со слипами не понятно

То, что тесты проходят, не гарантирует правильность кода. Особенно если это многопоточность.
Самая плохая бага- которая случается в одном случае из миллиона- на тестах не поймать, в проде- пожалуйста, будет приходить.
Непонимание этого- уже достаточная причина отказать.
А ваша агрессия- причина не объяснять отказ.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514893
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey TominquestionerА вас не смущает, что я тесты запускал и они проходили? Как это связано со слипами не понятно

То, что тесты проходят, не гарантирует правильность кода. Особенно если это многопоточность.
Самая плохая бага- которая случается в одном случае из миллиона- на тестах не поймать, в проде- пожалуйста, будет приходить.
Непонимание этого- уже достаточная причина отказать.
А ваша агрессия- причина не объяснять отказ.

20765509

Судя по сообщению человека с ником Vimba у него виснет некий код. Судя по всему всегда. Имхо он либо виснет либо нет.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514901
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimbaнапервый взгляд нигде не сказано, что удалять из мапы нельзя находясь внутри compute

автор /**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
* mapping). The entire method invocation is performed atomically.
* Some attempted update operations on this map by other threads
* may be blocked while computation is in progress, so the
* computation should be short and simple, and must not attempt to
* update any other mappings of this Map.

*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514904
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimba сначала исключите зависание, вызванное тем что whenComplete может вызваться внутри compute, из-за того что фьюча уже закомплечена.

Поясните что это и зачем, как вы решили, что это неправильно.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514916
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
questionervimba сначала исключите зависание, вызванное тем что whenComplete может вызваться внутри compute, из-за того что фьюча уже закомплечена.

Поясните что это и зачем, как вы решили, что это неправильно.

Ок, действительно такое имеет место быть.


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
 System.out.println("Main thread:" + Thread.currentThread().getId());
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                System.out.println("Before sleep thread:" + Thread.currentThread().getId());
                Thread.sleep(100);
                System.out.println("After sleep");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread.sleep(1000);
        future.whenComplete((r, e) -> System.out.println("whenCompleted thread:" + Thread.currentThread().getId()));


авторMain thread:1
Before sleep thread:11
After sleep
whenCompleted thread:1


Только они этого не нашли)

Надо подумать как это решить... из спортивного интереса
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514950
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerОк, действительно такое имеет место быть.

Ваше решение- по сути своей хак.
Такой код нельзя пускать в production. Он чрезвычайно неочевиден.
Можно терпеть медленный код, но нельзя непонятный.
Тут дискутировать нечего- это вопрос вкуса. Работает или нет- уже вторично, на самом деле.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514951
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Код: sql
1.
        taskMap.compute(key, (k, queue) -> {



На самом деле имя "queue" для этого параметра- уже смертный приговор.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39514989
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey TominВаше решение- по сути своей хак.
Такой код нельзя пускать в production. Он чрезвычайно неочевиден.
Можно терпеть медленный код, но нельзя непонятный.
Тут дискутировать нечего- это вопрос вкуса. Работает или нет- уже вторично, на самом деле.

у всех свои критерии понятности... У меня был отослан понятный код если что(как раз на этот случай). Передаём параметром количество потоков и создаём в соответствии с этим столько же очередей и воркеров и по хешу от ключа - кидаем в очередь. Но тут сказали, что распределение не нравится и судя по всему второе решение понравилось больше.

Да и заказчику зачастую на%?#ть понятно написано или нет - лишь бы работало. Как объясните заказчику, что есть рабочий непонятный код, который быстро работает, а есть медленный, но понятный. Думаю заказчик выберет быстрый вариант, если для него это критично. Но я опять же не агитирую писать непонятную ахинею. Я вообще не очень согласен, что код совсем уж непонятный. не простой - да, но и задача не самая очевидная не очень то делится на подзадачи.

Alexey Tominquestioner
Код: sql
1.
        taskMap.compute(key, (k, queue) -> {



На самом деле имя "queue" для этого параметра- уже смертный приговор.

Почему?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515004
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerДа и заказчику зачастую на%?#ть понятно написано или нет - лишь бы работало.

Вас оценивали потенциальные коллеги. Они не заказчики, им важна понятность.

questionerAlexey Tominпропущено...
На самом деле имя "queue" для этого параметра- уже смертный приговор.
Почему?

Потому что это не очередь, а элемент, за котором будет исполнена наша задача. Или та, что исполняется- понять сразу я это не смог, а вчитыватся и тестировать нет желания. В общем- queue это конкретный элемент очереди, а не очередь. Нельзя путать понятия в именах переменных.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515019
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: 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.
public class ThreadPoolImpl implements ThreadPool {
    private Logger logger = LoggerFactory.getLogger(ThreadPoolImpl.class);
    private final ConcurrentMap<String, CompletableFuture<Void>> taskMap = new ConcurrentHashMap<>();
    private volatile boolean isStopped = false;
    private final ThreadPoolExecutor poolExecutor;

    public ThreadPoolImpl(int threadCount) {
        poolExecutor = new ThreadPoolExecutor(threadCount, threadCount, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
    }

    @Override
    public void execute(MyTask myTask) {
        if (isStopped) {
            throw new IllegalStateException("Pool already terminated");
        }
        final String key = myTask.getKey();
        taskMap.compute(key, (k, queue) -> {
            logger.info("Key " + key + " compute started");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            CompletableFuture<Void> future = (queue == null)
                    ? CompletableFuture.runAsync(() -> {
                myTask.run();
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    logger.error("Thread pool thread was interrupted", e);
                }
            }, poolExecutor)
                    : queue.whenCompleteAsync((r, e) -> {
                myTask.run();
                try {
                    countDownLatch.await();
                } catch (InterruptedException ex) {
                    logger.error("Thread pool thread was interrupted", ex);
                }
            }, poolExecutor);
            //to prevent OutOfMemoryError in case if we will have too much keys
            future.whenComplete((r, e) -> taskMap.remove(key, future));
            countDownLatch.countDown();        
            logger.info("Key " + key + " compute finished");

            return future;
        });
    }



Вот кстати рабочий вариант, который исключает ситуацию, что задача закончилась до того, как мы прилепили ей коллбэк
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515023
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Код: java
1.
2.
3.
4.
        taskMap.compute(key, (k, queue) -> {
...
                    countDownLatch.await();
...


Вот кстати рабочий вариант, который исключает ситуацию, что задача закончилась до того, как мы прилепили ей коллбэк

Т.е. опять- пишут "метод должен отрабатывать как можно быстрее", а тут await.
Не, я понимаю, тут может всё достаточно быстро, но нафига писать такой код? Его трудно понимать, трудно поддерживать.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515025
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey TominquestionerДа и заказчику зачастую на%?#ть понятно написано или нет - лишь бы работало.

Вас оценивали потенциальные коллеги. Они не заказчики, им важна понятность.


По разному бывает.

Вообще странно как-то писать, что у вас не работает корректно детально то-то и то-то, а по факту подразумевать, что код не понятен. Не находите?
questionerпропущено...
Alexey TominПочему?

Потому что это не очередь, а элемент, за котором будет исполнена наша задача. Или та, что исполняется- понять сразу я это не смог, а вчитыватся и тестировать нет желания. В общем- queue это конкретный элемент очереди, а не очередь. Нельзя путать понятия в именах переменных.

То, что Вы не смогли это сразу понять ещё не значит, что это непонятно написано.

Скажем есть список рукописный и у вас есть ссылка на голову. Нельзя назвать эту ссылку list ? Этот аргумент по сути является очередью задач, а для меня ожидателем выполнения всей очереди до этого элемента включительно. Именование дело такое... как не назови - все не поймут, но мне кажется я постарался.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515027
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey Tominquestioner
Код: java
1.
2.
3.
4.
        taskMap.compute(key, (k, queue) -> {
...
                    countDownLatch.await();
...


Вот кстати рабочий вариант, который исключает ситуацию, что задача закончилась до того, как мы прилепили ей коллбэк

Т.е. опять- пишут "метод должен отрабатывать как можно быстрее", а тут await.
Не, я понимаю, тут может всё достаточно быстро, но нафига писать такой код? Его трудно понимать, трудно поддерживать.

Предложите вариант получше? я не смог просто. Думаете я стараюсь посложнее специально написать?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515053
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerAlexey Tominпропущено...
Вас оценивали потенциальные коллеги. Они не заказчики, им важна понятность.

По разному бывает.

Не понял. Что, кто-то любит непонятный код в репозитории? Не знаю, я бы не хотел там работать...

questionerВообще странно как-то писать, что у вас не работает корректно детально то-то и то-то, а по факту подразумевать, что код не понятен. Не находите?

1. Я оцениваю код, а не тех, кто оценивал код
2. Может там и ошибка. Мне не хочется разбираться.

questionerСкажем есть список рукописный и у вас есть ссылка на голову. Нельзя назвать эту ссылку list ?

head, по-моему, правильнее. Например потом, что queue не может быть null. А head - может.

questionerПредложите вариант получше? я не смог просто. Думаете я стараюсь посложнее специально написать?

Не знаю. В соседней теме я показал то, что написал за неполный час.
По мне- так намного проще. Возможно чуть медленнее, но для начала точно хватит.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515071
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey Tominquestionerпропущено...

По разному бывает.

Не понял. Что, кто-то любит непонятный код в репозитории? Не знаю, я бы не хотел там работать...


Этот комментарий относился к тому, что иногда оценивают коллеги, а иногда и заказчику могут заслать.

Alexey TominquestionerВообще странно как-то писать, что у вас не работает корректно детально то-то и то-то, а по факту подразумевать, что код не понятен. Не находите?

1. Я оцениваю код, а не тех, кто оценивал код
2. Может там и ошибка. Мне не хочется разбираться.

Собственно суть топика в том, чтобы обсудить аргументацию. Да, дополнительно обсудить какие-то другие решения тоже интересно.


Alexey TominquestionerСкажем есть список рукописный и у вас есть ссылка на голову. Нельзя назвать эту ссылку list ?

head, по-моему, правильнее. Например потом, что queue не может быть null. А head - может.

Согласен, но это название допустимо всё же.
Alexey TominquestionerПредложите вариант получше? я не смог просто. Думаете я стараюсь посложнее специально написать?

Не знаю. В соседней теме я показал то, что написал за неполный час.
По мне- так намного проще. Возможно чуть медленнее, но для начала точно хватит.

Для какого начала? это тестовое задание) Тем более вариант попроще и попонятнее я и так имею и он был вместе с этим отправлен. То, что там могут быть коллизии ребятам не понравилось.


EmptyLock не используется у вас нигде кроме комментариев. зачем он?
что такое "conflict" error ?

Ваша имплементация нарушает требования тестового задания, что все задачи должны выполняться в порядке прихода. Это на первый взгляд
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515079
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey Tomin,

Код: java
1.
executorService.submit(() -> executeTask(task));


будет тратить поток на все ключи без исключения.

То есть подряд идущие
key1
key1
key2

займут 3 потока вместо 2-ух. Но я думаю Вы это понимаете. Первое моё решение как-раз ругали из-за подобной "неоптимальности"
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515097
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЭтот комментарий относился к тому, что иногда оценивают коллеги, а иногда и заказчику могут заслать.

Заказчик либо не читает, либо тоже смотрит понятность кода.

questionerAlexey TominНе знаю. В соседней теме я показал то, что написал за неполный час.
По мне- так намного проще. Возможно чуть медленнее, но для начала точно хватит.

EmptyLock не используется у вас нигде кроме комментариев. зачем он?
что такое "conflict" error ?

Ваша имплементация нарушает требования тестового задания, что все задачи должны выполняться в порядке прихода. Это на первый взгляд

Это был пример теста вообще-то, а задания я не читал. Комментарий- это чтобы тест уронить.

В любом случае- не надо использовать методы Map для того, чтобы ставить задания в очередь. Это не то.

Их аргументацию обсуждать мне не интересно, т.к. они здесь не пишут.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515116
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey TominquestionerЭтот комментарий относился к тому, что иногда оценивают коллеги, а иногда и заказчику могут заслать.

Заказчик либо не читает, либо тоже смотрит понятность кода.

questionerпропущено...


EmptyLock не используется у вас нигде кроме комментариев. зачем он?
что такое "conflict" error ?

Ваша имплементация нарушает требования тестового задания, что все задачи должны выполняться в порядке прихода. Это на первый взгляд

Это был пример теста вообще-то, а задания я не читал. Комментарий- это чтобы тест уронить.

В любом случае- не надо использовать методы Map для того, чтобы ставить задания в очередь. Это не то.

Их аргументацию обсуждать мне не интересно, т.к. они здесь не пишут.

Им были заданы вопросы, на которые им некогда отвечать) Так что считаю обсудить тут вполне корректно. К тому же имён я не раскрывал.

А зачем вы скинули пример теста если мы сейчас обсуждаем имплементацию экзекутора?

Ну в общем суть в том, что "для начала сойдёт" - не сошло) Как я уже писал - решение с подобным перформансом было и оно не удовлетворило проверяющих.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515147
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerТолько они этого не нашли)

Надо подумать как это решить... из спортивного интереса

Код: java
1.
whenCompleteAsync() ?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515151
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Что-то я не понимаю как должен taskMap.remove() вообще работать в приведенном коде? Он же на каждую задачу в цепочке будет вызываться, даже если там есть ещё задачи, мы всю цепочку по ключу удалим?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515159
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerТолько они этого не нашли)

Надо подумать как это решить... из спортивного интереса

Код: java
1.
whenCompleteAsync() ?


Да, годится. По коду так попроще конечно будет и никаких новых race condition от этого я не вижу.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515161
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey TominНа самом деле имя "queue" для этого параметра- уже смертный приговор.
Поддержу. В одном методе два разных Future и у них абсолютно ни о чем не говорящие имена queue и future. Почему было бы не назвать last/tail и next, например?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515162
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowiczquestioner,

Что-то я не понимаю как должен taskMap.remove() вообще работать в приведенном коде? Он же на каждую задачу в цепочке будет вызываться, даже если там есть ещё задачи, мы всю цепочку по ключу удалим?

task.remove удаляет не по ключу, а по ключу и значению.

Если значение(фьюча) поменялась, то ничего удалится
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515164
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
questioner,


questionerЕсли значение(фьюча) поменялась, то ничего удалится
Если значение(фьюча) поменялась, то ничего НЕ удалится
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515166
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,

Это на мой взгляд самая хитрая часть этого кода и было потрачено много времени, чтобы придумать эту конструкцию
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515167
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЕсли значение(фьюча) поменялась, то ничего НЕ удалится
Точно. Спасибо.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515183
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerВ jdk ConcurrentHashMap compute не может исполняться Параллельно для ключей из одного бакета.
Этим мы расписываемся в том что решение не устойчиво к атаке на hash collision?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515184
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey TominВас оценивали потенциальные коллеги. Они не заказчики, им важна понятность.

Да, стоило написать явно на чем именно ключи синхронизируются.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515206
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerВ jdk ConcurrentHashMap compute не может исполняться Параллельно для ключей из одного бакета.
Этим мы расписываемся в том что решение не устойчиво к атаке на hash collision?

Это же инфраструктурный класс. Кому придёт в голову его атаковать?

К тому же ничего уж сильно плохого не случится. Добавление в мапу и создание парочки фьючей не такая уж и тяжёлая операция по сравнению с самой задачей.
BlazkowiczДа, стоило написать явно на чем именно ключи синхронизируются.

То, что всё это работает на очереди фьючей? комментарии в коде имеете ввиду или что-то типа сопроводительного письма?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515214
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Это же инфраструктурный класс. Кому придёт в голову его атаковать?

К тому же ничего уж сильно плохого не случится. Добавление в мапу и создание парочки фьючей не такая уж и тяжёлая операция по сравнению с самой задачей.


Чисто теоретически можно деградировать вашу систему до sequential состояния, а это уже косяк. Не агритесь, вам дело говорят. Да и вообще интервью с заданием на многопоточность это лотерея, ну не прошли и ничего страшного, я тоже из 3 одно прохожу хоть и опыта хватает)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515216
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЭто же инфраструктурный класс. Кому придёт в голову его атаковать?

Мы не знаем источника ключей.

questionerК тому же ничего уж сильно плохого не случится. Добавление в мапу и создание парочки фьючей не такая уж и тяжёлая операция по сравнению с самой задачей.

Ну, тогда бы и решение с synchronized подошло бы?

questionerТо, что всё это работает на очереди фьючей? комментарии в коде имеете ввиду или что-то типа сопроводительного письма?
В документации сказано что compute атомарный и всё. Стоило указать в коде что мы полагаемся на это поведение, ожидая синхронизацию для ключа исходя из атомарности.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515224
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Придется ждать vimba, я тоже не вижу как параллельно запустить задачи с одним ключом.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515228
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerЭто же инфраструктурный класс. Кому придёт в голову его атаковать?

Мы не знаем источника ключей.

questionerК тому же ничего уж сильно плохого не случится. Добавление в мапу и создание парочки фьючей не такая уж и тяжёлая операция по сравнению с самой задачей.

Ну, тогда бы и решение с synchronized подошло бы?


Вы утрируете.

Synchronized - всё в один поток и многопоточности нет тогда.
допустим у нас большой объём разных ключей, которые валятся в один бакет, но при этом они в основном разные.
Грубо говоря можно представить, что в данной есть один тред, который занимается маршрутизацией, то есть создаёт фьючи только, а сами таски выполняются в экзекуторе в отдельных тредах. Или Вы про Collections.synchronizedMap ? тогда да, то же самое. Но это на мой взгляд не такая уж и большая проблема.

Не очень понял Ваш пассаж. Что Вы имеете ввиду?

BlazkowiczquestionerТо, что всё это работает на очереди фьючей? комментарии в коде имеете ввиду или что-то типа сопроводительного письма?
В документации сказано что compute атомарный и всё. Стоило указать в коде что мы полагаемся на это поведение, ожидая синхронизацию для ключа исходя из атомарности.

автор Some attempted update operations on this map by other threads
may be blocked while computation is in progress, so the
computation should be short and simple, and must not attempt to
update any other mappings of this Map.

Согласен, что явно этого не сказано, но намёк очень явен. В принципе да, согласен, если бы написал - они бы уточнили, проверили и не написали бы то, что написали
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515231
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerSynchronized - всё в один поток и многопоточности нет тогда.

Ну, при коллизии hash кодов у нас будет compute всегда synchronized. То есть распределение таски по очередям полностью синхронизировано. Разницы вот с этим кодом нет:

Код: java
1.
2.
3.
synchronized(this) {
  taskMap.compute(lambda);
}
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515239
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerSynchronized - всё в один поток и многопоточности нет тогда.

Ну, при коллизии hash кодов у нас будет compute всегда synchronized. То есть распределение таски по очередям полностью синхронизировано. Разницы вот с этим кодом нет:

Код: java
1.
2.
3.
synchronized(this) {
  taskMap.compute(lambda);
}



Согласен, но распределение это обычно маленькая часть от работы. Во многих случаях это нормально.

А Вы можете предложить более производительный вариант?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515243
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczquestionerSynchronized - всё в один поток и многопоточности нет тогда.

Ну, при коллизии hash кодов у нас будет compute всегда synchronized. То есть распределение таски по очередям полностью синхронизировано. Разницы вот с этим кодом нет:

Код: java
1.
2.
3.
synchronized(this) {
  taskMap.compute(lambda);
}


Очень показательно, кстати - обсуждать какую-то высосанную из пальца несуществующую проблему и при этом без зазрения совести писать synchronized(this)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515248
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А то что ThreadPoolImpl#stop() никак не влияет на уже засабмиченные таски и внутренний экзекутор, уже кто-нибудь здесь отписывал?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515251
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TОчень показательно, кстати - обсуждать какую-то высосанную из пальца несуществующую проблему и при этом без зазрения совести писать synchronized(this)
Не читал но осуждаю? Перечитай ещё раз если ничего не понял.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515255
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TА то что ThreadPoolImpl#stop() никак не влияет на уже засабмиченные таски и внутренний экзекутор, уже кто-нибудь здесь отписывал?
Да, мне тоже не нравится собственный флаг. Я бы пулу потоков его делегировал.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515260
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei TА то что ThreadPoolImpl#stop() никак не влияет на уже засабмиченные таски и внутренний экзекутор, уже кто-нибудь здесь отписывал?

Да, у меня такой экзекутор, который просто прекращает новые таски принимать. Считаете, что надо таски на полпути прерывать? Такое тоже возможно, но зачем если это не часть задания?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
public class ThreadPoolExecutor extends AbstractExecutorService {
 ...
 /**
     * Initiates an orderly shutdown in which previously submitted
     * tasks are executed, but no new tasks will be accepted.
     * Invocation has no additional effect if already shut down.
     *
     * <p>This method does not wait for previously submitted tasks to
     * complete execution.  Use {@link #awaitTermination awaitTermination}
     * to do that.
     *
     * @throws SecurityException {@inheritDoc}
     */
    public void shutdown() {



Этого вообще в задании не было



Andrei Очень показательно, кстати - обсуждать какую-то высосанную из пальца несуществующую проблему и при этом без зазрения совести писать synchronized(this)
Показательно, что некоторые люди без зазрения совести могут оставить писать критичные сообщения на форуме даже если ни черта не понимают
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515264
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerДа, у меня такой экзекутор, который просто прекращает новые таски принимать. Считаете, что надо таски на полпути прерывать?

Ну, по-хорошему, если этого в задании нет, то можно было сделать параметром класса.
shutdown() запущные задачи не прерывает. Но те что в очереди уже не будут выполнятся.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515269
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerДа, у меня такой экзекутор, который просто прекращает новые таски принимать. Считаете, что надо таски на полпути прерывать?

Ну, по-хорошему, если этого в задании нет, то можно было сделать параметром класса.
shutdown() запущные задачи не прерывает. Но те что в очереди уже не будут выполнятся.

Можно, только зачем на это время тратить если никто не просил?

я имел ввиду, что никто не делает interrupt тредам. Да, если бы сделал это, конечно, было бы больше похоже на jdk тредпул, но не считаю это проблемой. я вообще это сделал, чтобы приложение у меня заканчивало работу.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515273
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerAndrei TА то что ThreadPoolImpl#stop() никак не влияет на уже засабмиченные таски и внутренний экзекутор, уже кто-нибудь здесь отписывал?

Да, у меня такой экзекутор, который просто прекращает новые таски принимать. Считаете, что надо таски на полпути прерывать? Такое тоже возможно, но зачем если это не часть задания?

Не надо никого прерывать на полпути. Важно отменить накопившуюся очередь задач, которая в реальной системе может быть значительного размера. Иначе твой экзекутор будет продолжать выполнять ранее засабмиченные задачи еще продолжительное время после вызова stop().

questionerAndrei Очень показательно, кстати - обсуждать какую-то высосанную из пальца несуществующую проблему и при этом без зазрения совести писать synchronized(this)
Показательно, что некоторые люди без зазрения совести могут оставить писать критичные сообщения на форуме даже если ни черта не понимают
Ты какой-то нервный. Что конкретно, по-твоему, я не понимаю? Не то что бы мне было очень интересно, но раз уж нахамил, было бы логично продолжить мысль.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515274
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAndrei TОчень показательно, кстати - обсуждать какую-то высосанную из пальца несуществующую проблему и при этом без зазрения совести писать synchronized(this)
Не читал но осуждаю? Перечитай ещё раз если ничего не понял.
Что в твоей писуле можно не понять? this - это ThreadPoolImpl из изначального поста?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515276
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerBlazkowiczпропущено...

Ну, по-хорошему, если этого в задании нет, то можно было сделать параметром класса.
shutdown() запущные задачи не прерывает. Но те что в очереди уже не будут выполнятся.

Можно, только зачем на это время тратить если никто не просил?

я имел ввиду, что никто не делает interrupt тредам. Да, если бы сделал это, конечно, было бы больше похоже на jdk тредпул, но не считаю это проблемой. я вообще это сделал, чтобы приложение у меня заканчивало работу.
Ты не считай, а сделай Thread.sleep(Integer.MAX_VALUE) в таске и проверь, как твое приложение закончит работу.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515277
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerМожно, только зачем на это время тратить если никто не просил?
Ну, как это никто не просил. Флаг же зачем-то добавили? Значит нужен корректный шатдаун?

questionerя имел ввиду, что никто не делает interrupt тредам.

Это понятно. Interrupt будет только в shutdownNow(), в shutdown() его не будет.

questionerя вообще это сделал, чтобы приложение у меня заканчивало работу.
Ну, вот есть задача разработать очередь задачь. Она как бы и подразумевает что очередь должне уметь корректно завершаться.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515279
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TЧто в твоей писуле можно не понять? this - это ThreadPoolImpl из изначального поста?
Что это тебя писули забеспокоили? Это демонстрация поведения, а не код для использования. Но не только лишь все могут понять.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515284
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei TBlazkowiczпропущено...

Не читал но осуждаю? Перечитай ещё раз если ничего не понял.
Что в твоей писуле можно не понять? this - это ThreadPoolImpl из изначального поста?
Код: java
1.
2.
3.
synchronized(this) {
  taskMap.compute(lambda);
}


Ок, объясню, попробую хотя бы.

Мапа делится на сегменты. То есть сегмент это кусочек мапы. Так вот, в ConcurrentHashMap мутабельные операции для сегмента выполняются последовательно.

Но важно понимать, что эта последовательная операция достаточно короткая. Сами таски выполняются в отдельных тредах.

А невежливы к Вам потому, что Вы прилетели с бухты барахты, нихрена не разобрались и начали критиковать.
Опять же, можете лучше предложить решение?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515290
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerМожно, только зачем на это время тратить если никто не просил?
Ну, как это никто не просил. Флаг же зачем-то добавили? Значит нужен корректный шатдаун?

questionerя имел ввиду, что никто не делает interrupt тредам.

Это понятно. Interrupt будет только в shutdownNow(), в shutdown() его не будет.

questionerя вообще это сделал, чтобы приложение у меня заканчивало работу.
Ну, вот есть задача разработать очередь задачь. Она как бы и подразумевает что очередь должне уметь корректно завершаться.

Ок, согласен, что не уделил этому аспекту большого внимания ибо посчитал его малозначащим в рамках этой задачи.

Вопрос как корректно останавливать тредпул это всё же вопрос дискуссионный. в рамках этой задачи я посчитал, что задачи важны и нельзя заканчивать работу пока есть необработанные задачи.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515302
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вимба, тем временем, не пришел. :(
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515305
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAndrei TЧто в твоей писуле можно не понять?
Что это тебя писули забеспокоили?
Ты так говоришь, как будто это что-то плохое. Код люди разной ориентации пишут, знаешь ли. В приличном обществе твой юмор бы не оценили. Но на отечественном форуме ты, конечно, просто записной остряк.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515311
vimba
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
    ...
    myTask.run();
    try {
          countDownLatch.await();
    } catch (InterruptedException e) {
          logger.error("Thread pool thread was interrupted", e);
    }
    ...


Вот кстати рабочий вариант ...

Нерабочий. questioner в пул кидают(в основном) долгоиграющие таски, верно? А какая по твоему самая распространенная в нашем мире причина, по которой таска планировалась выполняться долго, но завершилась моментально сразу после своего запуска? Переписывай с на try/finally короче.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515317
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerAndrei Tпропущено...

Что в твоей писуле можно не понять? this - это ThreadPoolImpl из изначального поста?
Код: java
1.
2.
3.
synchronized(this) {
  taskMap.compute(lambda);
}


Ок, объясню, попробую хотя бы.

Мапа делится на сегменты. То есть сегмент это кусочек мапы. Так вот, в ConcurrentHashMap мутабельные операции для сегмента выполняются последовательно.

Но важно понимать, что эта последовательная операция достаточно короткая. Сами таски выполняются в отдельных тредах.
Я, если честно, про твои сегменты и время операций даже не думал. synchronized(this) - это хорошо известный антипаттерн (в большинстве случаев). Обычно сходятся на том, что следует явно указывать модификатор synchronized в сигнатуре public метода.

questionerА невежливы к Вам потому, что Вы прилетели с бухты барахты, нихрена не разобрались и начали критиковать.
Опять же, можете лучше предложить решение?

Я никуда не прилетал, это, на секундочку, общий форум, а не твой личный чат (хотя я не навязываюсь). Мне твое решение как раз изначально понравилось как компактное и элегантное, о чем я написал еще на первой странице (и там же - об еще одной баге, которую я изначально заметил). Также я тебе в другой твоей теме про экзекутор скидывал ссылку на свой код на гитхабе, который решает примерно те же задачи, что стоят перед тобой.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515319
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimba,

Ну допустим. там уже предложили вариант полаконичнее с whenCompleteAsync
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515321
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei T,
Andrei TЯ, если честно, про твои сегменты и время операций даже не думал. synchronized(this) - это хорошо известный антипаттерн (в большинстве случаев). Обычно сходятся на том, что следует явно указывать модификатор synchronized в сигнатуре public метода.
Вот мы и поняли, что не думал, а это очень важно. А взял и осудил)

Вторую часть фразы я пожалуй не буду комментировать.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515325
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimba,

Код: java
1.
2.
3.
4.
5.
6.
7.
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("Task with exception");
            throw new RuntimeException();
        });
        Thread.sleep(100);

        future.whenCompleteAsync((r, e) -> System.out.println("Main thread"));



авторTask with exception
Main thread

Если имелось ввиду то, что whenComplete(Async) может не выполниться, то это не правда
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515326
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
    public static void main(String[] args) throws InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task with exception");
            throw new RuntimeException();
        });
        Thread.sleep(100);

        future.whenCompleteAsync((r, e) -> System.out.println("Main thread"));
        Thread.sleep(2000);


авторTask with exception
Main thread


Ну и так тоже
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515343
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TЯ, если честно, про твои сегменты и время операций даже не думал. synchronized(this) - это хорошо известный антипаттерн (в большинстве случаев). Обычно сходятся на том, что следует явно указывать модификатор synchronized в сигнатуре public метода.

Пипец. Капитан очевидность не унимается. Тут вообще-то все в курсе как использовать synchronized. Это была иллюстрация того как будет работать код при коллизии хэшей.
Термин "иллюстрация" объяснить?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515363
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerСогласен, но распределение это обычно маленькая часть от работы. Во многих случаях это нормально.
А Вы можете предложить более производительный вариант?
А "производительность" она в многопоточности штука относительная. Мы же не знаем ни на сколько конкурентной будет борьба за критические ресурсы, ни на сколько часто у будут пересекаться ключи. В зависимости от подобных параметров разные решения будут выдавать разную производительность.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515366
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczquestionerСогласен, но распределение это обычно маленькая часть от работы. Во многих случаях это нормально.
А Вы можете предложить более производительный вариант?
А "производительность" она в многопоточности штука относительная. Мы же не знаем ни на сколько конкурентной будет борьба за критические ресурсы, ни на сколько часто у будут пересекаться ключи. В зависимости от подобных параметров разные решения будут выдавать разную производительность.

Согласен, Вы считаете, что текстом нужно было это отразить?

Как по мне это решение явно не проигрывает никакому из тех, что мне в голову пришли. Если бы у меня для одного распределения было решение явно лучше, чем для другого, то я бы это указал. Может какие то решения и будут лучше, но явно не на порядок и надо садиться и измерять, а тут ведь явно была задача на алгоритм.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515368
vimba
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionervimba,

Ну допустим. там уже предложили вариант полаконичнее с whenCompleteAsync

С whenCompleteAsync у меня все мои тесты прошли нормально, нет проблем не с утечками паямити, не с паралельным выполнением по одному ключу, не с бесконечным зацикливанием. Думаю ситуация с ревью развивалась следующим образом: у них есть набор заковыристых тестов, включая и таски падающие с эксепшенами и таски мгновенно завершающиеся, тесты пофэйлились потому, что у тебя тред повис из-за remove внутри compute, профилировать не стали(а я твой код пронаблюдал в Mission Control где он у тебя зависает), и просто быстро просмотрев код отписали самое на первый взгляд очевидное - проблема в remove, не доглядев как и я что remove не просто по ключу.

В общем я бы на твоем месте сильно не обижался не проверяющих, потому что в коде бага была, и даже с первого раза ты её правильно не исправил.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515389
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAndrei TЯ, если честно, про твои сегменты и время операций даже не думал. synchronized(this) - это хорошо известный антипаттерн (в большинстве случаев). Обычно сходятся на том, что следует явно указывать модификатор synchronized в сигнатуре public метода.

Пипец. Капитан очевидность не унимается. Тут вообще-то все в курсе как использовать synchronized. Это была иллюстрация того как будет работать код при коллизии хэшей.
Термин "иллюстрация" объяснить?
Эк тебя бомбит. Где тут, кстати, можно ознакомиться с перечнем того, о чем еще все в курсе?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515390
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЕсли имелось ввиду то, что whenComplete(Async) может не выполниться, то это не правда
Наверно все-таки имелось в виду то, что надо делать так:

Код: java
1.
2.
3.
4.
5.
try {
    myTask.run();
} finally {
    countDownLatch.await();
}



Иначе возникает race condition между экзекутором и тредом, выполняющим compute, и как следствие блокировка с зависанием в отдельных случаях.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515392
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimbaquestionervimba,

Ну допустим. там уже предложили вариант полаконичнее с whenCompleteAsync

С whenCompleteAsync у меня все мои тесты прошли нормально, нет проблем не с утечками паямити, не с паралельным выполнением по одному ключу, не с бесконечным зацикливанием. Думаю ситуация с ревью развивалась следующим образом: у них есть набор заковыристых тестов, включая и таски падающие с эксепшенами и таски мгновенно завершающиеся, тесты пофэйлились потому, что у тебя тред повис из-за remove внутри compute, профилировать не стали(а я твой код пронаблюдал в Mission Control где он у тебя зависает), и просто быстро просмотрев код отписали самое на первый взгляд очевидное - проблема в remove, не доглядев как и я что remove не просто по ключу.

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

Ну это недочёт)

Не то, чтобы я действительно искал работу, меня моя работа вполне устраивает.
Просто интересно было решить задание и было время для этого. Я потратил время и решил таки задачу. Я считаю, что я решение придумал и это самое главное, а мелочи небольшие...так без этого никуда. А мне ответили, что я всё не так сделал и идея неправильная. Ну если вы уж даёте такую задачу - будьте в ней экспертами.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515393
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei TquestionerЕсли имелось ввиду то, что whenComplete(Async) может не выполниться, то это не правда
Наверно все-таки имелось в виду то, что надо делать так:

Код: java
1.
2.
3.
4.
5.
try {
    myTask.run();
} finally {
    countDownLatch.await();
}



Иначе возникает race condition между экзекутором и тредом, выполняющим compute, и как следствие блокировка с зависанием в отдельных случаях.
я думаю это по другому называется) просто произойдёт зависание в случае если таска выплюнет эксекпшн
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515396
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerAndrei Tпропущено...

Наверно все-таки имелось в виду то, что надо делать так:

Код: java
1.
2.
3.
4.
5.
try {
    myTask.run();
} finally {
    countDownLatch.await();
}



Иначе возникает race condition между экзекутором и тредом, выполняющим compute, и как следствие блокировка с зависанием в отдельных случаях.
я думаю это по другому называется) просто произойдёт зависание в случае если таска выплюнет эксекпшн
Даже если не выплюнет, а просто выполнится раньше, чем будет привязан колбэк. На второй странице это обсуждали. В принципе не суть важно, как это называть, но обычно зависимость результата от порядка выполнения кода в многопоточной среде называют именно так :)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515409
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei Tquestionerпропущено...

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

Если просто раньше выполнится - всё будет Ok
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515413
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerAndrei Tпропущено...

Даже если не выплюнет, а просто выполнится раньше, чем будет привязан колбэк. На второй странице это обсуждали. В принципе не суть важно, как это называть, но обычно зависимость результата от порядка выполнения кода в многопоточной среде называют именно так :)

Если просто раньше выполнится - всё будет Ok
Ты вроде сам уже проверял, что Ок не будет: 20769167
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515414
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообще вам с Blazkowicz стоит подумать об открытии адвокатской конторы. Что-нибудь типа "Blazkowicz и партнеры". Вот уж где пригодится манера спорить до усрачки с любым утверждением собеседника.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515423
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerСогласен, Вы считаете, что текстом нужно было это отразить?

Как по мне это решение явно не проигрывает никакому из тех, что мне в голову пришли.

Поэтому надо написать самый простой вариант и текстом дописать, мол "тут возможная таая-то проблема с перформансом, если вылезет- поменяйте так".
Вы не понимаете важность простоты. Может придёт со временем.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515425
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЯ считаю, что я решение придумал и это самое главное, а мелочи небольшие...так без этого никуда. А мне ответили, что я всё не так сделал и идея неправильная.

Полгода назад я сказал "надо брать" посмотрев ошибочный код человека. Потому что он попросил (и я ему дал) задачу, слишком сложную для него. Код был с ошибкой, но читался легко и приятно.
За эти полгода я ни разу не пожалел- он и пишет отличный (в т.ч. быстрый и правильный) код, и ревьювит другой код отлично.
Не так сложно научится писатьработающий код. А вот научится писать простой и поддерживаемый код намного сложнее.
У Вас код именно плохо поддерживаемый. И Вы этого непонимаете.

questionerНу если вы уж даёте такую задачу - будьте в ней экспертами.

Вы применили совершенно неожиданный подход. Знать его заранее было невозможно, а разбираться сложнл. Да и не нужно.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515440
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TВообще вам с Blazkowicz стоит подумать об открытии адвокатской конторы. Что-нибудь типа "Blazkowicz и партнеры". Вот уж где пригодится манера спорить до усрачки с любым утверждением собеседника.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515444
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey TominПоэтому надо написать самый простой вариант и текстом дописать, мол "тут возможная таая-то проблема с перформансом, если вылезет- поменяйте так".
Вы не понимаете важность простоты. Может придёт со временем.
Полностью поддерживаю. Уже несколько лет за собой замечаю, что основное время при кодинге трачу на поиск наиболее простого решения. Но в данном конкретном случае можно и поспорить. Я бы начал реализовывать через putIfAbsent и явные очереди, а не цепочку Futures. Но есть серьезные подозрения, что проще не получится.

Давайте конкретизируем. Что именно в приведенном решение "сложно"? Кроме синхронизации через атомарный compute(), по-моему, ничего. И в данном случае этот момент легко было бы исправить комментарием в коде. Мол compute атомарный и тем самым гарантирует синхронизацию по ключу.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515445
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczДавайте конкретизируем. Что именно в приведенном решение "сложно"? Кроме синхронизации через атомарный compute(), по-моему, ничего. И в данном случае этот момент легко было бы исправить комментарием в коде. Мол compute атомарный и тем самым гарантирует синхронизацию по ключу.

Именно что compute. Он служит для управления содержимом map'ы. А тут мы управляем, по сути, очередью задач.
Т.е. в решении есть "очередь", но она реализована неявно а вставка- через метод map'ы.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515450
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey TominИменно что compute. Он служит для управления содержимом map'ы. А тут мы управляем, по сути, очередью задач.
Т.е. в решении есть "очередь", но она реализована неявно а вставка- через метод map'ы.

whenCompleteAsync() это "очередь"
compute() это синхронизация

Если дать переменным более логичные имена и вставить пару комментариев, то будет намного более понятно.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515463
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAlexey TominИменно что compute. Он служит для управления содержимом map'ы. А тут мы управляем, по сути, очередью задач.
Т.е. в решении есть "очередь", но она реализована неявно а вставка- через метод map'ы.

whenCompleteAsync() это "очередь"
compute() это синхронизация

Если дать переменным более логичные имена и вставить пару комментариев, то будет намного более понятно.

Да, может быть вся проблема в плохих именах и недостатке небольшого описания.
Получается, что красивая идея полностью загублена такой вроде фигнёй.
Но именно что загублена напрочь, т.е. код стал плохим.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515499
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAlexey TominИменно что compute. Он служит для управления содержимом map'ы. А тут мы управляем, по сути, очередью задач.
Т.е. в решении есть "очередь", но она реализована неявно а вставка- через метод map'ы.

whenCompleteAsync() это "очередь"
compute() это синхронизация

Если дать переменным более логичные имена и вставить пару комментариев, то будет намного более понятно.

Blazkowicz, направьте меня, я не пойму, где синхронизация, questioner пишет "Это довольно легко проверить если сделать Thread.sleep внутри compute и сделать из разных потоков put с одинаковыми ключами.", но это как раз и вводит "искусственную синхронизацию". По мне, автор задания правильно описал ошибку.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515504
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0FDBlazkowicz, направьте меня, я не пойму, где синхронизация, questioner пишет "Это довольно легко проверить если сделать Thread.sleep внутри compute и сделать из разных потоков put с одинаковыми ключами.", но это как раз и вводит "искусственную синхронизацию". По мне, автор задания правильно описал ошибку.

Согласно документации метод compute() выполняется атомарно . На практике это обозначает что для разных ключей метод исполняется пареллельно, а для ключей из одного бакета, метод блокируется. По-моему это единственный, возможный, недостаток.
Это и есть та самая синхронизацию по ключу.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515510
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczСогласно документации метод compute() выполняется атомарно . На практике это обозначает что для разных ключей метод исполняется пареллельно, а для ключей из одного бакета, метод блокируется. По-моему это единственный, возможный, недостаток.
Это и есть та самая синхронизацию по ключу.

Да, но здесь блокируется на время создания future, а taskMap.remove разве не выполняется в потоке myTask( который выполняет complete), запущенной из CompletableFuture.runAsync?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
public void execute(MyTask myTask) {
        if (isStopped) {
            throw new IllegalStateException("Pool already terminated");
        }
        final String key = myTask.getKey();
        taskMap.compute(key, (k, queue) -> {
            CompletableFuture<Void> future = (queue == null)
                    ? CompletableFuture.runAsync(myTask, poolExecutor)
                    : queue.whenCompleteAsync((r, e) -> myTask.run(), poolExecutor);
            //to prevent OutOfMemoryError in case if we will have too much keys
            future.whenComplete((r, e) -> taskMap.remove(key, future));
            return future;
        });
    }
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515515
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0FDДа, но здесь блокируется на время создания future, а taskMap.remove разве не выполняется в потоке myTask( который выполняет complete), запущенной из CompletableFuture.runAsync?
Ну, так в этом же и основная ошибка была. taskMap.remove() надо было вызывать через whenCompleteAsync(), чтобы он случайно не выполнился внутри compute().
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515522
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz0FDДа, но здесь блокируется на время создания future, а taskMap.remove разве не выполняется в потоке myTask( который выполняет complete), запущенной из CompletableFuture.runAsync?
Ну, так в этом же и основная ошибка была. taskMap.remove() надо было вызывать через whenCompleteAsync(), чтобы он случайно не выполнился внутри compute().

Я честно, не читал все, но если taskMap.remove() в whenCompleteAsync(), тогда где блокировка? нет future - создали-запустили-вышли, есть - по окончании запустили остальные.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515525
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0FDЯ честно, не читал все
Ну, да. Отличный повод повторить.

0FD, но если taskMap.remove() в whenCompleteAsync(), тогда где блокировка?
Внутри compute()
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/concurrent/ConcurrentHashMap.java
Строки 1868 и 1848.

0FDнет future - создали-запустили-вышли, есть - по окончании запустили остальные.
Блокировка не на выполнение, а только на постановку в очередь.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515528
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei Tquestionerпропущено...


Если просто раньше выполнится - всё будет Ok
Ты вроде сам уже проверял, что Ок не будет: 20769167

Ну ты опять ничего не понял)


Код: java
1.
2.
3.
4.
CountDownLatch countDownLatch = new CountDownLatch(1);
countDownLatch.countDown();
countDownLatch.await();
System.out.println("after await");


так работает нормально.


По ссылке проблема в том, что колбэк должен был выполняться в треде таски и поэтому перед завершением этой таски я жду когда compute вызовет whenComplete. Если whenComplete вызвался когда таска уже завершилась, то коллбэк выховется в треде compute.

а твой код
Код: java
1.
2.
3.
4.
5.
try {
    myTask.run();
} finally {
    countDownLatch.await();
}



решает проблему если эксепшн вылетит.

Теперь понятно?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515533
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
0FDBlazkowiczСогласно документации метод compute() выполняется атомарно . На практике это обозначает что для разных ключей метод исполняется пареллельно, а для ключей из одного бакета, метод блокируется. По-моему это единственный, возможный, недостаток.
Это и есть та самая синхронизацию по ключу.

Да, но здесь блокируется на время создания future, а taskMap.remove разве не выполняется в потоке myTask( который выполняет complete), запущенной из CompletableFuture.runAsync?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
public void execute(MyTask myTask) {
        if (isStopped) {
            throw new IllegalStateException("Pool already terminated");
        }
        final String key = myTask.getKey();
        taskMap.compute(key, (k, queue) -> {
            CompletableFuture<Void> future = (queue == null)
                    ? CompletableFuture.runAsync(myTask, poolExecutor)
                    : queue.whenCompleteAsync((r, e) -> myTask.run(), poolExecutor);
            //to prevent OutOfMemoryError in case if we will have too much keys
            future.whenComplete((r, e) -> taskMap.remove(key, future));
            return future;
        });
    }



Выяснили, что если CompletableFuture.runAsyn уже закончилось к строке
future.whenComplete то тело whenComplete будет вызвано в треде compute
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515534
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

Спасибо, да, не вовремя я подключился.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515537
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey Tomin,

Алексей Вы специально игнорируете мои сообщения? вот напрочь игнорируете - не понимаю зачем.

Я уже не раз писал, что

1. БЫЛО ОТПРАВЛЕНО ПРОСТОЕ НО МЕНЕЕ ПРОИЗВОДИТЕЛЬНОЕ РЕШЕНИЕ. С КОЛЛИЗИЯМИ. ИМ НЕ ПОНРАВИЛОСЬ ПО ПЕРФОРМАНСУ. ВСЕГО Я ОТПРАВИЛ 2!!!!! (ДВА) РЕШЕНИЯ Там код не сложнее вашего, только под все условия подходит. Второе решение реально более сложное и производлительное и пришлось почесать репу, чтобы его придумать.

А Вы будто поставили задачу оправдать этих проверяющих))

Я кстати замечу, что никто (от слова абсолютно) не предложил решения похожего по распределению задач, но более простого. Ну а к наименованию придираться можно конечно, но если тебе что-то непонятно можно спросить товарища, который это писал. Нейминг это не точная наука.

А по поводу того, что проверяющие не обязаны разбираться - ну как бы смешно. Задачу придумать они могут, простое решение не достаточно производительное, поэтому очевидно, что будет не что-то простое им отправлено и им должно хватать квалификации разбираться в том, что они задали. А так получилось, что они сами не разобрались в чем проблема. А в работе как будет? тесты упали, оооо да там всё не так, давайте всё перепишем, а там условно не хватает одного volatile
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515539
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrei TquestionerЕсли имелось ввиду то, что whenComplete(Async) может не выполниться, то это не правда
Наверно все-таки имелось в виду то, что надо делать так:

Код: java
1.
2.
3.
4.
5.
try {
    myTask.run();
} finally {
    countDownLatch.await();
}



Иначе возникает race condition между экзекутором и тредом, выполняющим compute, и как следствие блокировка с зависанием в отдельных случаях.

Andrei Tquestionerпропущено...

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

finally не влияет на race condition-ы
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515589
vimba
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

А у тебя бенчмарков случаем не осталось? Я чуть покрутил твой алгоритм, заменив CompletableFuture на не синхронизированную очередь(синхронизация уже провайдится compute ) и внёс(на мой взгляд) ряд оптимизиций:
Шедуля таску не надо каждые раз возвращать новый маппинг для мапы, если уже есть таска в прогрессе то просто возвращаем уже сушествующую очередь жаждущих выполнится на том же самом ключе, что позволяет не аллоцировать новый узел для мапы если уже есть таска с таким ключем в прогрессе.

Отказ от фьюч позволил совместить compute и remove в одно целое, воспользовавшись свойством того, что если compute возвращает null то entry удалается из мапы, тобишь whenCompleteAsync стал вообще не нужным, не нужно на кажду таску вкидывать в пул еще одну таску, абсолютный win на мой взгляд по CPU и аллокациям
Код: 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.
private final ConcurrentHashMap<String, Queue<Task>> taskMap = new ConcurrentHashMap<>();

        public void execute(Task task) {
            taskMap.compute(task.getKey(), (key, queue) -> {
                if (queue == null) {
                    // это первая таска с ключом, создаем очередь для тех кто пожелает присоседится 
                    // пока текущая таска в прогрессе
                    queue = new LinkedList<>();
                    poolExecutor.execute(new DecoratedTask(task));
                    return queue;
                } else {
                    queue.add(task);
                    // возвращаем ту же очередь, маппинг остается нетронутым, новый узел не аллоцируюется
                    return queue;
                }
            });
        }

        private class DecoratedTask implements Runnable {
            private final Task target;

            public DecoratedTask(Task target) {
                this.target = target;
            }

            @Override
            public void run() {
                try {
                    target.run();
                } finally {
                    taskMap.compute(target.getKey(), (key, queue) -> {
                        Task nextTask = queue.poll();
                        if (nextTask == null) {
                            // ждущих тасок по этому же ключу нет просто удаляем узел из мапы
                            return null;
                        }
                        try {
                            poolExecutor.execute(new DecoratedTask(nextTask));
                        } finally {
                            return queue;
                        }
                    });
                }
            }
        }


Но надо признаться, что я этот код еще не тестил, потому что тесты дома остались, и естественно как предполагал Blazkowicz кода меньше не стало, стало только больше.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515602
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimba,

я не бенчмаркил. Очень поверхностные замеры только были. тут это не поможет.

в этом решении удаление блочит бакет зато и случается абсолютно для каждой таски. А в моём варианте оно происходит параллельно с задачами из бакета и вообще не происходит в случае если фьча по этому ключу поменялась(то есть новая задача подкинулась по этому ключу).

Но на каких-то входных данных всё же видимо заработает быстрее. Думаю на реалистичных задачах он будут работать одинаково)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515656
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vimbaкак предполагал Blazkowicz кода меньше не стало, стало только больше.
Ну, если так писать, то да. Но, что-то мне подсказывает что можно и так, например:
Код: java
1.
2.
3.
4.
5.
public void execute(Task task) {
    queueMap
        .computeIfAbsent(task.getKey(), this::scheduleNewQueue)
        .add(task);
}
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515706
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А, давайте оптимизациями меряться!

Код: 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.
    ConcurrentHashMap<String, Queue<Runnable>> queueMap = new ConcurrentHashMap<>();
    ExecutorService threadPool = Executors.newCachedThreadPool();

    public boolean execute(Task task) {
        return !this.threadPool.isShutdown()
                && this.queueMap
                    .computeIfAbsent(task.getKey(), this::scheduleNewQueue)
                    .add(wrapped(task));
    }

    public void stop() {
        this.threadPool.shutdown();
    }

    private Queue<Runnable> scheduleNewQueue(String key) {
        ConcurrentLinkedQueue<Runnable> queue = new ConcurrentLinkedQueue<>();
        this.threadPool.submit(() -> {
            do {
                for (Runnable task : queue) task.run();
            } while (thereAreTasks(key, queue));
        });
        return queue;
    }

    private boolean thereAreTasks(String key, ConcurrentLinkedQueue<Runnable> queue) {
        return queueMap.compute(key, (k, v) -> queue.isEmpty() ? null : queue) != null;
    }

    private Runnable wrapped(Task task) {
        return () -> {
            try {
                task.run();
            } catch (Throwable e) {
                task.fail(e);
            }
        };
    }
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515733
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

Код: java
1.
2.
3.
do {
    for (Runnable task : queue) task.run();
} while (thereAreTasks(key, queue));


Рано или поздно здесь выскочит ConcurrentModificationException
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515738
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerBlazkowicz,

Это на мой взгляд самая хитрая часть этого кода и было потрачено много времени, чтобы придумать эту конструкцию

Извините, что так поздно, но мне кажется, что вы не ответили на показанный vimba спорный кусок кода
Код: 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.
public class Test {

  private final static ConcurrentMap<String, CompletableFuture<Void>> taskMap = new ConcurrentHashMap<>();

  public static void main(String[] args) {

   final String key = "test1";

   System.out.println("Should be empty in map: " + taskMap.get(key));

   taskMap.compute(key, (k, queue) -> {
            System.out.println("Key " + key + " compute started");
            final CompletableFuture<Void> future=new CompletableFuture();
            System.out.println("Our future : " + future);
            //to prevent OutOfMemoryError in case if we will have too much keys
            future.whenComplete((r, e) -> {
                        System.out.println("Result in map then complete: " + taskMap.get(key));
                        System.out.println(" try to remove ...");
            		taskMap.remove(key, future);
		}
            );
            System.out.println("Lets ensure how it works if have finished already...");
            future.complete(null);
            System.out.println("Key " + key + " compute finished and removed!");
            return future;
        });
    System.out.println("Result in map: " + taskMap.get(key));
  }

}



А потом сделайте финту ушами и закомментируйте taskMap.remove(key, future);
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515744
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TРано или поздно здесь выскочит ConcurrentModificationException
Полюбому выскочит. Надо циклы объединить и poll использовать. Но, блин, через poll уродливо выходит.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515745
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TBlazkowicz,

Код: java
1.
2.
3.
do {
    for (Runnable task : queue) task.run();
} while (thereAreTasks(key, queue));


Рано или поздно здесь выскочит ConcurrentModificationException
Вообще-то нет, вру.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515747
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei T,

Путаешь меня почем зря.
javadocIterators are <i>weakly consistent</i>, returning elements
reflecting the state of the queue at some point at or since the
creation of the iterator.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515751
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевИзвините, что так поздно, но мне кажется, что вы не ответили на показанный vimba спорный кусок кода
Вроде, три раза уже ответили: whenCompleteAsync()
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515753
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczAndrei T,

Путаешь меня почем зря.
javadocIterators are <i>weakly consistent</i>, returning elements
reflecting the state of the queue at some point at or since the
creation of the iterator.
Да, ввел в заблуждение всех, сорян
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515758
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei TДа, ввел в заблуждение всех, сорян
Но, там всё равно через poll() должно эффективнее работать.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515770
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczВроде, три раза уже ответили: whenCompleteAsync()
Как это влияет на то, что из мапы пытаются удалить что-то до того, как туда его вставили?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515775
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
            future.whenCompleteAsync((r, e) -> {
                        System.out.println("Result in map then complete: " + taskMap.get(key));
                        System.out.println(" try to remove ...");
            		taskMap.remove(key, future);
                        System.out.println("Result in map then remove: " + taskMap.get(key));
		}
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515776
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Result in map then remove: null
Final result in map: java.util.concurrent.CompletableFuture@3e3abc88[Completed normally]
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515778
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевКак это влияет на то, что из мапы пытаются удалить что-то до того, как туда его вставили?
Хороший вопрос. А ведь и правда.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515857
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczСергей АрсеньевКак это влияет на то, что из мапы пытаются удалить что-то до того, как туда его вставили?
Хороший вопрос. А ведь и правда.

Это влияет на то в каком треде будет происходить удаление.

Тогда только летч поможет.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515861
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowiczvimbaкак предполагал Blazkowicz кода меньше не стало, стало только больше.
Ну, если так писать, то да. Но, что-то мне подсказывает что можно и так, например:
Код: java
1.
2.
3.
4.
5.
public void execute(Task task) {
    queueMap
        .computeIfAbsent(task.getKey(), this::scheduleNewQueue)
        .add(task);
}



порядок мне кажется может нарушиться


1ый тред сделал computeIfAbsent
2ый тред сделал computeIfAbsent

...
2ый тред добавил в очередь
1ый тред добавил в очередь

но это мелочь
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515882
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczAndrei TРано или поздно здесь выскочит ConcurrentModificationException
Полюбому выскочит. Надо циклы объединить и poll использовать. Но, блин, через poll уродливо выходит.
а что с poll-ом не так?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515904
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczА, давайте оптимизациями меряться!
на мой взгляд стало хуже. Вот здесь задачи с одинаковым ключом получают преимущество в планировании:
Код: java
1.
2.
3.
            do {
                for (Runnable task : queue) task.run();
            } while (thereAreTasks(key, queue));


А вот здесь
Код: java
1.
  for (Runnable task : queue) task.run();


из очереди ничего удаляться не будет, for loop же не удаляет из Queue ничего, если предположить что вы забыли удалить задачу тем или иным образом (ну там poll вместо for loop), то все равно беда, потому что вот здесь:
Код: java
1.
  .add(wrapped(task));


к моменту вызова add очередь может быть уже пустой, и ничего выполняться уже не будет.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515905
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЭто влияет на то в каком треде будет происходить удаление.
У меня это влияет и на то, вызовется потом новый whenCompleteAsync (другими словами будет ли запущен следующая задача с тем же ключом) или нет. В одном запуске теста вызывается, в другом нет. Т.е. не только утечка памяти по отработанным ключам, но и потеря задач.

Я б не мудрствовал бы и просто сделал очередь задач. И разгребальщик с мапой для работающих.

Правда ошибок бы понасажал поначалу... :)
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515916
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевquestionerЭто влияет на то в каком треде будет происходить удаление.
У меня это влияет и на то, вызовется потом новый whenCompleteAsync (другими словами будет ли запущен следующая задача с тем же ключом) или нет. В одном запуске теста вызывается, в другом нет. Т.е. не только утечка памяти по отработанным ключам, но и потеря задач.



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


Сергей АрсеньевЯ б не мудрствовал бы и просто сделал очередь задач. И разгребальщик с мапой для работающих.

Правда ошибок бы понасажал поначалу... :)

Можно как-то поподробнее?
есть очередь, есть мапа. Как они связаны? мапа очередей или очередь мап?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515927
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerМожно как-то поподробнее?
есть очередь, есть мапа. Как они связаны? мапа очередей или очередь мап?
есть очередь.
есть однопотоковый разгребатель.
у него есть мапа списков задач.
Если в мапе ключей <N выбираем следующую задачу из очереди и проверяем есть ли ее ключ.
(DCL все такое :) )
Нет добавляем в мапу список из нашей таски и запускаем ее, добавляем ея в список.
Таска по окончании себя вычеркивает и запускает следующую, а если таковой не было, то и ключ из мапы.

Долго, нудно, не интересно. :(
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515954
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerа что с poll-ом не так?
Всё так. Просто кода больше и он менее понятен.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515960
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфилов,

Спасибо за комментарии. Цикл, действительно, нужно переделать. Про удаление не подумал. И про добавление тоже верно. Хотелось его убрать из синхронизации, но, похоже, не выйдет.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515970
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А можно про планирование пояснить, пожалуйста? Откуда возьмется преимущество, там же на каждый ключ отдельная фьюча?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515977
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczЦикл, действительно, нужно переделать.Разве что из спортивного интереса, по изначальным условиям для одинаковых ключей должен быть реализован fair scheduling, а у ConcurrentHashMap под капотом synchronized на нодах, никаким fair тут и не пахнет.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515979
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei T,

это замечание про 20772870 - там задачи с одним ключем выполняются в одном for loop без каких-либо дополнительных задержек, т.е. если если представить что душеприказчик у нас однопоточный, то поведение у него будет несколько странным.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515980
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфилов,

В однопоточном экзекуторе понятно, а когда несколько потоков? Хотя, кажется, я понимаю: пока задач (ключей) не больше чем потоков, задачи будут выполняться равномерно, а как только число задач превысит количество потоков, то задачи, добавленные позже, будут ждать в очереди экзекутора, пока не выполнятся добавленные ранее. Верно?
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515984
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrei T,

наоборот: если для ключа "K" существует "живая" очередь задач, то все новые задачи с таким же ключом "К" будут добавлены в эту очередь и могут быть потенциально выполнены раньше других задач. Представьте что банк обслуживает такие счета: один счет наркоторговцев, один счет контробандистов и 100 счетов законопослушных граждан. Через первые два счета у нас постоянно идут транзакции ввиду особенностей бизнеса их владельцев, душеприказчиков у нас тоже два, при таком соотношении транзакции законопослушных граждан выполняться не будут, потому что душеприказчики будут заняты транзакциями наркодиллеров и конробандистов
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39515987
Andrei T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфилов,

Ну да, я это и имел в виду (под задачами подразумевал задачу с циклом в экзекуторе, а не пришедший извне Task). Спасибо!
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39518478
vimba
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczА, давайте оптимизациями меряться!
Давайте, это очень интересно. Только questioner потерял бенчмарки(или не писал их изначально), поэтому нужно, чтобы кто-то из нас пожертвовал своим личным временем и написал бенчи. Или можно создать репу на гитхабе и написать их совместно.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39519081
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vimba,

Да, не писал, не было такого задания)

К тому честно говоря не приходилось никогда
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39522275
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Версия без локов (ну понятное дело мб в блокингкуе или конкаррент хэшпэме они используются внутри):
Код: 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.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
public class TesPool {

    private final ProcessingThread[] threads;
    private volatile boolean isShutdown = false;
    private final AtomicInteger pendingTasks = new AtomicInteger();
    private final ConcurrentMap<Object, TaskStuff> cm = new ConcurrentHashMap<Object, TaskStuff>();

    private final TaskStuff ZEROCOUNTTASKSTUFF = new TaskStuff(0, null);

    public TesPool(int size) {
        ProcessingThread[] pool = new ProcessingThread[size];
        for(int i = 0; i < size; i++) {
            pool[i] = new ProcessingThread();
            pool[i].setDaemon(true);
        }
        threads = pool;
    }

    public void start() {
        for(Thread thread : threads) {
            thread.start();
        }
    }

    public boolean shutdown() {
        isShutdown = true;
        while(true) {
            int shut = 0;
            for(Thread th : threads) {
                if(!th.isAlive()) {
                    shut++;
                }
            }
            if(shut == threads.length) {
                return true;
            }
            LockSupport.parkNanos(300);
        }
    }

    public void submit(Actionee action) throws RejectedExecutionException {
        pendingTasks.incrementAndGet();
        if(isShutdown) {
            pendingTasks.decrementAndGet();
            throw new RejectedExecutionException("shutdown!");
        }

        TaskStuff newTs = new TaskStuff(0, null);
        TaskStuff currentTs = null;
        Random rnd = new Random();
        do {
            newTs.setCount(1);
            newTs.setThread(threads[Math.abs(rnd.nextInt()) % threads.length]);
            currentTs = cm.putIfAbsent(action.getKey(), newTs);
            if(currentTs == null) {
                break;
            }
            newTs.setCount(currentTs.getCount() + 1);
            newTs.setThread(currentTs.getThread());
        } while(!cm.replace(action.getKey(), currentTs, newTs));
        newTs.getThread().submitToThread(action);
    }

    public class ProcessingThread extends Thread {

        private final BlockingQueue<Actionee> blockingQueue = new LinkedBlockingQueue<Actionee>();

        @Override
        public void run() {
            while(!isShutdown || !blockingQueue.isEmpty() || pendingTasks.get() != 0) {
                while(true) {
                    Actionee actionee = blockingQueue.poll();
                    if(actionee == null) {
                        break;
                    }
                    try {
                        actionee.run();
                    } catch(Exception ex) {
                        ex.printStackTrace();
                    } finally {
                        TaskStuff newTs = new TaskStuff(0, this);
                        while(true) {
                            TaskStuff ts = cm.get(actionee.getKey());
                            newTs.setCount(ts.getCount() - 1);
                            if(cm.replace(actionee.getKey(), ts, newTs)) {
                                break;
                            }
                        }
                        cm.remove(actionee.getKey(), ZEROCOUNTTASKSTUFF);
                    }
                }
                LockSupport.parkNanos(300);
            }
        }

        public void submitToThread(Actionee actionee) {
            try {
                blockingQueue.add(actionee);
            } finally {
                pendingTasks.decrementAndGet();
            }
        }
    }

    private static class TaskStuff {
        private int count;
        private ProcessingThread thread;

        public TaskStuff(int count, ProcessingThread thread) {
            this.count = count;
            this.thread = thread;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        public ProcessingThread getThread() {
            return thread;
        }

        public void setThread(ProcessingThread thread) {
            this.thread = thread;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            TaskStuff taskStuff = (TaskStuff) o;

            return count == taskStuff.count;
        }
    }

    public interface Actionee extends Runnable {
        Object getKey();
    }

    // тесты
    public static void main(String[] args) throws Exception {
        final TesPool tp = new TesPool(256);
        tp.start();
        for(int i = 0; i < 5; i++) {
            long begin = System.currentTimeMillis();
            final CountDownLatch cdlDone = new CountDownLatch(100000);
            new Thread() {
                @Override
                public void run() {
                    final Random rdm = new Random();
                    for (int i = 0; i < 100000; i++) {
                        tp.submit(new Actionee() {

                            private final int key;

                            {
                                key = rdm.nextInt();
                            }

                            @Override
                            public Object getKey() {
                                return key;
                            }

                            @Override
                            public void run() {
                                try {
                                    Thread.sleep(1);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                } finally {
                                    cdlDone.countDown();
                                }
                            }
                        });
                    }
                }
            }.start();
            cdlDone.await();
            /*Map<ProcessingThread, Integer> thSet = new HashMap<ProcessingThread, Integer>();
            for(TaskStuff taskStuff : tp.cm.values()) {
                if(thSet.containsKey(taskStuff.getThread())) {
                    thSet.put(taskStuff.getThread(), thSet.get(taskStuff.getThread()) + taskStuff.getCount());
                } else {
                    thSet.put(taskStuff.getThread(), taskStuff.getCount());
                }
            }
            int total = 0;
            for(Map.Entry<ProcessingThread, Integer> entry : thSet.entrySet()) {
                total += entry.getValue();
                System.out.println("Thread : " + entry.getKey() + " count: " + entry.getValue());
            }
            System.out.println("Total threads used: " + thSet.size() + " total tasks: " + total);*/
            System.out.println("TotalDone: 100000"  + ", took: " + (System.currentTimeMillis() - begin) + " ms");
        }
        tp.shutdown();
    }

}


Тоесть 100000 задач, каждая по 1 мс, ключ - рандомный на интервале инт. Результаты на моем компе jdk1.8/linux/i7-3770:

1 поток:
TotalDone: 100000, took: 108565 ms
TotalDone: 100000, took: 108302 ms
TotalDone: 100000, took: 108142 ms
TotalDone: 100000, took: 108105 ms
TotalDone: 100000, took: 107872 ms
Если принять эталонное время выполнения 100000 ms, оверхед пула*: (107872-100000)/100000 = 7,87%

2 потока:
TotalDone: 100000, took: 54367 ms
TotalDone: 100000, took: 54239 ms
TotalDone: 100000, took: 54372 ms
TotalDone: 100000, took: 54366 ms
TotalDone: 100000, took: 54376 ms
Если принять эталонное время выполнения 50000 ms, оверхед пула*: (54239-50000)/50000 = 8,48%

4 потока:
TotalDone: 100000, took: 27285 ms
TotalDone: 100000, took: 27295 ms
TotalDone: 100000, took: 27372 ms
TotalDone: 100000, took: 27330 ms
TotalDone: 100000, took: 27115 ms
Если принять эталонное время выполнения 25000 ms, оверхед пула*: (27115-25000)/25000 = 8,46%

8 потоков:
TotalDone: 100000, took: 13633 ms
TotalDone: 100000, took: 13747 ms
TotalDone: 100000, took: 13703 ms
TotalDone: 100000, took: 13728 ms
TotalDone: 100000, took: 13718 ms
Если принять эталонное время выполнения 12500 ms, оверхед пула*: (13633-12500)/12500 = 9,06%

16 потоков:
TotalDone: 100000, took: 6971 ms
TotalDone: 100000, took: 6915 ms
TotalDone: 100000, took: 6897 ms
TotalDone: 100000, took: 6865 ms
TotalDone: 100000, took: 6993 ms
Если принять эталонное время выполнения 6250 ms, оверхед пула*: (6865-6250)/6250 = 9,84%

32 потоков:
TotalDone: 100000, took: 3510 ms
TotalDone: 100000, took: 3591 ms
TotalDone: 100000, took: 3481 ms
TotalDone: 100000, took: 3483 ms
TotalDone: 100000, took: 3491 ms
Если принять эталонное время выполнения 3125 ms, оверхед пула*: (3481-3125)/3125 = 11,39%

64 потока:
TotalDone: 100000, took: 1819 ms
TotalDone: 100000, took: 1790 ms
TotalDone: 100000, took: 1763 ms
TotalDone: 100000, took: 1748 ms
TotalDone: 100000, took: 1774 ms
Если принять эталонное время выполнения 1562 ms, оверхед пула*: (1748-1562)/1562 = 11,91%

Распределение задач по потокам (при 16):

Thread : Thread[Thread-15,5,main] count: 6264
Thread : Thread[Thread-10,5,main] count: 6233
Thread : Thread[Thread-11,5,main] count: 6228
Thread : Thread[Thread-2,5,main] count: 6392
Thread : Thread[Thread-5,5,main] count: 6260
Thread : Thread[Thread-4,5,main] count: 6307
Thread : Thread[Thread-14,5,main] count: 6291
Thread : Thread[Thread-1,5,main] count: 6224
Thread : Thread[Thread-0,5,main] count: 6234
Thread : Thread[Thread-3,5,main] count: 6213
Thread : Thread[Thread-13,5,main] count: 6139
Thread : Thread[Thread-12,5,main] count: 6176
Thread : Thread[Thread-7,5,main] count: 6176
Thread : Thread[Thread-6,5,main] count: 6193
Thread : Thread[Thread-8,5,main] count: 6320
Thread : Thread[Thread-9,5,main] count: 6350

Тестирование кустарное, но просто народ хочет цифр обычно. Плюс надо было еще на всем выполнении кидать задачи, а то только вначале параллельно делается.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39522557
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892,

если забыть про отлов исключений и что при коллизиях меняется порядок выполнения, то у вас реализована не очередь, а несколько очередей.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39522959
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфиловno56892,

если забыть про отлов исключений и что при коллизиях меняется порядок выполнения, то у вас реализована не очередь, а несколько очередей.
Про исключения, а что конкретнее там не так? Что в консоль пишется?
Про коллизии - это никак не нарушает условие о том, что таски с одинаковыми ключами должны исполняться последовательно по их добавлению. Если Вы будете шарашить из 2+ потоков без синхронизации, там не может быть никакой гарантии и никакой ожидаемой последовательности.
Про то, что не очередь а несколько очередей - с точки зрения пользователя можно считать, что очередь, это детали реазизации, все равно то говорить ArrayList не список а массив.

Кстати, проблема в этой версии на самом деле есть небольшая (когда мало экзекьюторов): 2 экзекутора, добавляем 10 тасков с ключем 1 и 10 с ключем 2, с вероятностью в 50% второй ключ попадет на тот же поток на который и первый. Решается - использованием roundrobbin вместо рандома. Но и теперь есть штучка интересная допустим распределили 50 на 1й тред 50 на второй, а что если таски во втором завершаться а в первом еще нет - тогда второй будет простаивать, ну это вообще общая проблема для такого подхода. Решение, как говорили Выше (опять же без локов) дополнительный сервисный тред и очередь, в нее кидают клиенты, сервисный тред выбирает наименее загруженный и ктдает ему. Очень кстати хорошее решение. Ну или зафигачить локи, но это не итересно и банально.
...
Рейтинг: 0 / 0
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #39523194
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892Про коллизии - это никак не нарушает условие о том, что таски с одинаковыми ключами должны исполняться последовательно по их добавлению. Если Вы будете шарашить из 2+ потоков без синхронизации, там не может быть никакой гарантии и никакой ожидаемой последовательности.


Как по мне - нарушает. Если без синхронизации не может быть гарантии, значит синхронизация нужна.
...
Рейтинг: 0 / 0
140 сообщений из 140, показаны все 6 страниц
Форумы / Java [игнор отключен] [закрыт для гостей] / Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]