|
|
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1soncdtyjvпропущено... Если честно - я понятия не имею, что такое ExecutableQueue. Но это не мешает мне утверждать, что ваш код нужно выкинуть. Есть такое понятие - code smell. Это когда даже не вникая в то, что делает код, можно сказать, что он неверный, отталкиваясь от косвенных признаков. Так вот, ваш код очень сильно "смеллит". Я даже не хочу писать конкретные ошибки - их слишком много, и нет смысла их исправлять. Давайте так - объясните вашу задачу. и я накидаю вам нормальное решение. DOUBLE OMG. Нука хотябы одну ошибку в студию! Если вы даже не поняли что за класс перед вами , то что вы сможете объяснить ? Ссылаетесь не понятно на что. Код этот работает так: Например есть пул с 30 потоками. Приходит запрос ,в Селекторе читаем буффер и хандлим пакеты. Появились пакеты на отправку , добавляем их в эту очередь, при том это умная очередь которая способна распознать выполняются в ней пакеты или нет. То есть очередь не допустит что бы сразу 30 пакетов (запросов) не забрали все 30 потоков в пуле а достаточно что 1 поток обрабатывает всю очередь ... напишите мне альтернативу Этот способ я использовал в Lineage2 когда разбирал сервак. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:05:37 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjvMasterZivВходим в блок synchronized (events), events пуст, и мы начинаем ждать события на том же events. Но оно никогда не наступит, потому что взводится оно только в dispatchEvent(Event e), в другом блоке synchronized (events) , в который нельзя будет зайти, поскольку монитор events уже заблокирован.Коллега, я вынужден констатировать, что вы не знаете, как работает wait/notify. Когда вызывается wait(), то поток освобождает захваченный монитор , и помещается в wait set этого монитора. Поэтому в другой блок synchronized(events) можно будет зайти . Да, действительно. Геслинг скрестил ежа с ужом... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:15:58 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1sonНука хотябы одну ошибку в студию! Ошибка 1: Кривой дизайн. Коллекция имплементирует Runnable и хранит внутри себя Executor. Хотя должно быть с точностью наоборот: коллекция хранит внутри себя только элементы, не имплементирует Runnable, а какой-то Exeсutor вычитывает из нее. Ошибка 2: Переменная _state нe final => не безопасная публикация. Ошибка 3: isEmpty() и size() не обернуты в synchronized => могут возвращать совершенно некорректные результаты, вплоть до отрицательных величин. Но самая главная претензия - это, конечно, дизайн. Он ужасен. greenpo1sonКод этот работает так: Например есть пул с 30 потоками. Приходит запрос ,в Селекторе читаем буффер и хандлим пакеты. Появились пакеты на отправку , добавляем их в эту очередь, при том это умная очередь которая способна распознать выполняются в ней пакеты или нет. То есть очередь не допустит что бы сразу 30 пакетов (запросов) не забрали все 30 потоков в пуле а достаточно что 1 поток обрабатывает всю очередь ... напишите мне альтернативуПока условие непонятно. 1) Сколько может быть таких очередей в рамках одного экзекьютора? 2) Что плохого в том, что они будут хэндлить пакеты в параллель? То есть, почему плохо, что 30 пакетов разойдутся по 30 потокам в пуле? Пока что, до конца не понимая задачу, раз вам вы хотите исполнять в одном потоке, то вот решение: Код: java 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:47:11 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
MasterZivДа, действительно. Геслинг скрестил ежа с ужом...Не понял вашей мысли. Поведение wait/notify - это классическое условие в не менее классическом мониторе Хоара. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:48:39 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjv, Ошибка 3: isEmpty() и size() не обернуты в synchronized => могут возвращать совершенно некорректные результаты, вплоть до отрицательных величин. Это обрабатывается внутри кода. 2) Что плохого в том, что они будут хэндлить пакеты в параллель? То есть, почему плохо, что 30 пакетов разойдутся по 30 потокам в пуле? Представте себе что пользователь например игрок стреляет в игре , отходит ещё что нибудь делает , приходит пакеты запросы которые мы должны обработать в ПРАВИЛЬНОМ порядке! Если я сделаю так как вы предложили то подтверждение прыжка например придет быстрее чем подтверждения попадания в цель , хотя игрок с начала выстрелил,а только потом прыгнул. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:55:12 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
Точно такая же картина будет и у остальных игроков, у одного он прыгает у другого стреляет у 3 вообще летает )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:56:40 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1soncdtyjv, Ошибка 3: isEmpty() и size() не обернуты в synchronized => могут возвращать совершенно некорректные результаты, вплоть до отрицательных величин. Это обрабатывается внутри кода. 2) Что плохого в том, что они будут хэндлить пакеты в параллель? То есть, почему плохо, что 30 пакетов разойдутся по 30 потокам в пуле? Представте себе что пользователь например игрок стреляет в игре , отходит ещё что нибудь делает , приходит пакеты запросы которые мы должны обработать в ПРАВИЛЬНОМ порядке! Если я сделаю так как вы предложили то подтверждение прыжка например придет быстрее чем подтверждения попадания в цель , хотя игрок с начала выстрелил,а только потом прыгнул. И да не забывайте что мы все это записываем в ByteBuffer и если 30 потоков одновременно начнут записывать в 1 буффер то что произойдет ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 16:58:11 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1son, Хотя они конечно записываются только в Селекторе, пул только подготавливает пакеты к записи в буффер. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 17:01:52 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1son , Ок, ситуация проясняется. То есть вам нужен ордеринг в рамках одного игрока. Тогда вопрос такой: у вас сколько этих очередей? По одной на каждого игрока, или нет? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 18:08:55 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjv greenpo1son , Ок, ситуация проясняется. То есть вам нужен ордеринг в рамках одного игрока. Тогда вопрос такой: у вас сколько этих очередей? По одной на каждого игрока, или нет? У каждого игрока 2 очереди Одна Executable для принятых пакетов, пакет прочитали и сразу исполнили всю очередь. Второй простой ArrayDeque для содержание пакетов для отправки и добавления интересов в селектор (естественно синхронизованная) По сабжу я хотел предложить ТС просто немного переделать мою очередь под 1 поток и юзать его вместо листов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 18:28:20 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1son , Ок, понял вас. Тогда к вашему коду следующие претензии: 1) Зачем вы имплементируете Queue, когда бОльшую часть ее методов вам не нужна? В результате, в классе куча ненужного кода. 2) Представим, что вы купили себе новый сервак с 16 ядрами. И в приложении создали тред пул с 16 потоками, который будет обрабатывать игроков. Они начинают играть, ходят, чатятся, закупаются, и т.д. Вроде все круто. Потом наступает вечер войн гильдий. В игру входит 16 + 1 = 17 игроков. И в какой-то момент они начинают слать очень много команд на ваш сервер: деруться, применяют аптечки, кастуют что-то, и т.д. Но у вас всего 16 потоков в пуле. Каждый из этих потоков начинает обрабатывать одного игрока, и никак не может выйти из run(), так как команды прибывают быстрее, чем обрабатываются. Результат: 16 игроков воюют нормально, а 17й не может ничего сделать, так как ваш тред пул никак не дойдет до его очереди. Это называется starvation. 3) В продолжении п.2, если игроки шлют больше команд, чем вы можете обработать, то они скапливаются, и со временем у вас вылетает OOME (хотя, может быть эта защита стоит у вас где-то в другом месте кода). Я не знаю всех условий и особенностей вашей задачи, но я бы двигался примерно в таком направлении: Код: 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. То есть у нас есть класс TaskHolder с очень простым и понятным интерфейсом: добавить таск для конкретного игрока, получить список задач. Ваш NIO хэндлер закидывает сюда задачи, а какой-нибудь другой воркер в бесконечном цикле читает из taskGroupQueue(), и закидывает группу тасков в какой-нибудь executor. Все, никаких ненужных методов нет, очередь ничего не знает про executor и никак от него не зависит, есть защита от starvation, есть защита от OOME. Гонок вроде нет, но может быть я что-то и упустил. Автору ваш совет не подходит, так как ему запретили использовать j.u.c, плюс у вас совершенно разные задачи: вам надо создать очередь задач, а ему по сути надо сделать воркер, который будет обрабатывать задачи в бесконечном цикле. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 19:30:43 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjv greenpo1son , Ок, понял вас. Тогда к вашему коду следующие претензии: 1) Зачем вы имплементируете Queue, когда бОльшую часть ее методов вам не нужна? В результате, в классе куча ненужного кода. 2) Представим, что вы купили себе новый сервак с 16 ядрами. И в приложении создали тред пул с 16 потоками, который будет обрабатывать игроков. Они начинают играть, ходят, чатятся, закупаются, и т.д. Вроде все круто. Потом наступает вечер войн гильдий. В игру входит 16 + 1 = 17 игроков. И в какой-то момент они начинают слать очень много команд на ваш сервер: деруться, применяют аптечки, кастуют что-то, и т.д. Но у вас всего 16 потоков в пуле. Каждый из этих потоков начинает обрабатывать одного игрока, и никак не может выйти из run(), так как команды прибывают быстрее, чем обрабатываются. Результат: 16 игроков воюют нормально, а 17й не может ничего сделать, так как ваш тред пул никак не дойдет до его очереди. Это называется starvation. 3) В продолжении п.2, если игроки шлют больше команд, чем вы можете обработать, то они скапливаются, и со временем у вас вылетает OOME (хотя, может быть эта защита стоит у вас где-то в другом месте кода). Я не знаю всех условий и особенностей вашей задачи, но я бы двигался примерно в таком направлении: Код: 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. То есть у нас есть класс TaskHolder с очень простым и понятным интерфейсом: добавить таск для конкретного игрока, получить список задач. Ваш NIO хэндлер закидывает сюда задачи, а какой-нибудь другой воркер в бесконечном цикле читает из taskGroupQueue(), и закидывает группу тасков в какой-нибудь executor. Все, никаких ненужных методов нет, очередь ничего не знает про executor и никак от него не зависит, есть защита от starvation, есть защита от OOME. Гонок вроде нет, но может быть я что-то и упустил. Автору ваш совет не подходит, так как ему запретили использовать j.u.c, плюс у вас совершенно разные задачи: вам надо создать очередь задач, а ему по сути надо сделать воркер, который будет обрабатывать задачи в бесконечном цикле. Зачем это все? Во первых буффер не резиновый , а всего 32кб + кеш буфферов 64шт. Во вторых есть определенный тайм оут который определяет время первого пакета на отправку после которого пишутся пакеты, так же имеется ограничители на max кол-во пакетов и также размер запроса не может привышать 32кб (в 32кб может поместится около 500 пакетов) и если же начнется такой хаус (500 пакетов это уже не нормально, нормально считает 32 пакета за раз) то просто кикаем игрока. Ваш метод мне кажется не подходит, так как не допустимо ждать пока освободится место в очереди. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 20:03:56 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
1) Зачем вы имплементируете Queue, когда бОльшую часть ее методов вам не нужна? В результате, в классе куча ненужного кода. Для совместимости , и работа на уровне суперкласса как бы поощряется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 20:10:51 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1son1) Зачем вы имплементируете Queue, когда бОльшую часть ее методов вам не нужна? В результате, в классе куча ненужного кода. Для совместимости , и работа на уровне суперкласса как бы поощряется.Для совместимости с чем? И факт того, что вы имплементируете интерфейс коллекции таким образом, что: 1) Половина методов тупо не заимплементирована, включая iterator()!!! 2) Часть заимплементированных методов работают некорректно (size(), isEmpty(), ... не может поощряться. Это какой-то класс мутант, который вроде бы и коллекция ... но как коллекцию его использовать нельзя. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 20:43:04 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
greenpo1son Код: java 1. 2. 3. 4. 5. 6. 7. Вы постоянно присваиваете новый ArrayList? Да, это самопальный CopyOnWrite . Т.к. слушатели редко изменяются и часто читаются, то думаю подход оправдан. На сколько мне известно этот метод для слушателей в Свинге используется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 21:19:26 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjvgreenpo1son1) Зачем вы имплементируете Queue, когда бОльшую часть ее методов вам не нужна? В результате, в классе куча ненужного кода. Для совместимости , и работа на уровне суперкласса как бы поощряется.Для совместимости с чем? И факт того, что вы имплементируете интерфейс коллекции таким образом, что: 1) Половина методов тупо не заимплементирована, включая iterator()!!! 2) Часть заимплементированных методов работают некорректно (size(), isEmpty(), ... не может поощряться. Это какой-то класс мутант, который вроде бы и коллекция ... но как коллекцию его использовать нельзя. Все верно сделано потому что это не коллекция , а рабочий queue к которому прямого доступа из когда нету. Ему не нужен итератор, так все запросы обрабатываются в нем ,а не через него. То что я вам показал это всего 1% из всего кода. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 21:27:40 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
Для совместимости с чем? И факт того, что вы имплементируете интерфейс коллекции таким образом, что: С тем что любой другой программист может дописать или как то улучшить и просто поменять конкретный объект, а не весь связанный с ним код. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 21:29:52 |
|
||
|
Задача по многопоточности
|
|||
|---|---|---|---|
|
#18+
cdtyjvMasterZivДа, действительно. Геслинг скрестил ежа с ужом...Не понял вашей мысли. Поведение wait/notify - это классическое условие в не менее классическом мониторе Хоара. Зачем event сопрягать с семафором? Я на самом деле был бы очень благодарен, если бы ты мне разъяснил... Сегодня весь день над этим думал. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.09.2013, 23:12:49 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=38397173&tid=2128600]: |
0ms |
get settings: |
10ms |
get forum list: |
24ms |
check forum access: |
5ms |
check topic access: |
5ms |
track hit: |
39ms |
get topic data: |
18ms |
get forum data: |
3ms |
get page messages: |
93ms |
get tp. blocked users: |
2ms |
| others: | 356ms |
| total: | 555ms |

| 0 / 0 |
