powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
15 сообщений из 140, страница 6 из 6
Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
    #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
15 сообщений из 140, страница 6 из 6
Форумы / Java [игнор отключен] [закрыт для гостей] / Сказали, что выполнил тестовое задание неправильно, я с этим не согласен. Кто прав?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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