LINUX.ORG.RU

Тредпул и таски, таски, таски

 , ,


0

3

Все никак не додумаю правильную архитектуру отвечающую целям.

База:

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

Каждый таск перед его запуском будет отправлен в тредпул и в итоге выполнен в каком-то треде.

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

На завершение таска можно подписаться сигналом/каллбеком.

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

Цели:

Большое количество тасков разных типов обусловлено необходимостью сегментировать задачи на максимально маленькие. Что позволит выполнять параллельно больше работы.

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

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

В целом, это тоже не вызывает проблем в реализации.

Подводные камни:

Вижу два пути:

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

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

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

Атомики отпали сразу, т.к. состояние комплексное и поведение сильно зависит от типа таска.

Мьютексы/фьютексы/семафоры, да. Но, взяв самое медленное (мьютекс) возникает вопрос - не будут ли блокировки медленнее созданий-удалений?

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

Комплексно:

Свободные таски надо хранить в списке, по списку надо бежать, искать.

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

Чтобы узнать свободен ли таск нужно его сначала залочить. И так каждый в цикле.

Делать много списков где каждый хранит только конкретный тип (а типов дохрена, на крайняк группу близких типов?) тасков?

И, думается мне, это не преждевременная оптимизация, а лишь желание сделать сразу правильно, чтобы потом не переписывать много.

Да, надо бы тесты погонять. Не будут они сильно зависеть от проца, оси и прочего окружения?

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

Дай колбаски хлеб доесть, а?

pon4ik

★★★★★

Последнее исправление: deep-purple (всего исправлений: 1)
Ответ на: комментарий от anonymous

смотри.

на каждый тип таска создать свой контейнер, в каждом контейнере два списка - свободные и занятые, при обращении хоть один таск ищется в свободных, если нету - создается и перемещается/ вставляется в список занятых, по завершении перемещается в свободные.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от xpahos

спасибо! почитаю позже, щас уже спать надо

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

свободные и занятые

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

anonymous
()

Возьми уже готовое, рекомендую яблочный GCD

deadplace
()

Большое количество тасков разных типов обусловлено необходимостью сегментировать задачи на максимально маленькие. Что позволит выполнять параллельно больше работы.

Неверно.

Атомики отпали сразу, т.к. состояние комплексное и поведение сильно зависит от типа таска.

Тоже.

Как и всё остальное.

Вижу два пути:

Они несостоятельны.

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

Это будет последние, что будет тебя волновать.

Вообщем, основная твоя проблема это:

Большое количество тасков разных типов обусловлено необходимостью сегментировать задачи на максимально маленькие. Что позволит выполнять параллельно больше работы.

А далее уже нагромождение ещё больших глупостей на базе этой.

Особенно в контексте:

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

Это делает ситуацию ещё более нелепой.

Если кратко. Ты узнал где-то базворд «таск» и начал, ввиду полного отсутствия понимания, пихать его везде. Ты воспринимаешь это как какую-то отдельную сущность.

В конечном итоге -

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

Противоречит

Что позволит выполнять параллельно больше работы.

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

Реализуется это очень просто:

Выкидываешь это говно:

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

Сливаешь

Но они будут работать с разными данными

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

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

Синхронизировать тебе нужно именно логический уровень. У тебя уже есть идентификатор данных - это указатель. Далее тебе нужно прицепить к нему флаги. В указателе у тебя много свободных бит - действуй. Хотя я не вижу, что тебе нужен параллельный доступ к данным. Но базе флагом в указателе ты можешь реализовать локи на данных, как и много всего интересно.

Но самый простой и очевидный для тебя способ - организовать всё на базе готовых параллельных коллекция/контейнеров. В 99% тебе хватит очереди.

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

Во-вторых. Очередь избавить тебя от необходимости городить всю херню с обходом, локами данных и прочем. В данном случае для тебя это будет бесплатно. Избавляет она тем, что разбивает твои данные на группы.

anonymous
()
Ответ на: комментарий от anonymous

Свободные таски надо хранить в списке, по списку надо бежать, искать.

Ты хранишь не какие-то маня-таски, а данные. Причём не одна их порция, а много. Как найти N я уже писал.

Если у тебя генерация данных неравномерна по T, то на уровне генератора реализуй таймауты.

Чтобы узнать свободен ли таск нужно его сначала залочить. И так каждый в цикле.

Это какой-то нелепый набор слов. Свободны могут быть ресурсы, а не какой-то нелепый таск. Хотя даже в этом контексте - это бессмысленно.

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

Воркер сам себя сможет залочить, если ему это понадобиться. Обойти очереди и найти данные - он так же сможет сам.

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

Внутри же ты всё можешь организовать таким образом, что тебе этот мусор будет ненужен. Как максимум ты можешь заимпрувить спинлок sched_yield/sleep - это будет куда эффективнее локов(управляемых тобою).

anonymous
()
Ответ на: комментарий от anonymous

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

какое последовательное выполнение, ты що?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от anonymous

о, ты еще и таймауты предлагаешь ))

и отказаться от блокировок тоже предлагаешь - поиметь UB.

deep-purple ★★★★★
() автор топика

По описанию, тебе вполне подошёл бы стандартный крестовый std::async, если бы только он гарантированно использовал пул потоков. Но своё сделать несложно. Насчёт аллокаций уже сказали - решается специфичным аллокатором. Иначе во избежание «ко-ко-ко оверхеда» от аллокаций ты нагородишь какую-то дичь, которая освободившийся таск будет искать не быстрее, чем аллокатор кусок памяти. Еще и в concurrent access ошибёшься(не факт, конечно).

BTW, аллокатор писать возможно не придётся - boost::container::adaptive_pool скорее всего подойдёт.

P. S. С вероятностью 80% хватит стандартного аллокатора - он довольно неплох. Но то линуксы

anonymous
()
Ответ на: комментарий от anonymous

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

но я пока только думаю, еще почитать надо что народ покидал выше

deep-purple ★★★★★
() автор топика
Последнее исправление: deep-purple (всего исправлений: 1)
Ответ на: комментарий от deep-purple

Отпишись тогда по итогам. Тоже интересно, особенно если бэнчи будут

anonymous
()

std::async?

Если нефункциональные требования не высоки (не считаешь микросекунды и ниже) - то std::async (future, move, map) или поделки типа Objectizer как посоветовали выше. В противном случае видел я интересный «шаблон», но он требует классификации задач и построение дерева их очередей.

По факту тебе нужен планировщик задач и DSL для запуска и ожидания этих задач. Посмотри доклады яндексоидов со всяких цппрашша и прочих про то как они планируют задачи в своих корутинах, может наведёт на полезные мысли.

Мьютексы/фьютексы/семафоры, да. Но, взяв самое медленное (мьютекс) возникает вопрос - не будут ли блокировки медленнее созданий-удалений?

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

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

Тем не менее - лучше так, как минимум в poc решении. При этом - если о5 же позволяют нефункциональные требования лучшая политика хранения тут это просто shared_ptr.

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

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

Да, надо бы тесты погонять. Не будут они сильно зависеть от проца, оси и прочего окружения?

Не будет кроме нагрузочных тестов. Проектировать нужно так, что бы машина состояний планировщика минимум зависела от деталей реализации, тогда её можно будет покрыть обычными юнит тестами. Для точек где без многопотоков в тестах никак очень хороша работает связка gmock + Event(примитив который пишется на колене за 5 минут - с интерфейсом set, wait(timeout), reset).

Делать много списков где каждый хранит только конкретный тип (а типов дохрена, на крайняк группу близких типов?) тасков?

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

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

Вот бы ещё понять - чем данные отличаются от таска… Опять же, если у тебя будет список только задач, то непонятно как ты запустишь несколько задач одного типа параллельно. Проблемы с выделением памяти успешно решаются различными пуллами. Давно не замерял - но как пища для рамышлений - прямой поиск по массиву до 1000 элементов в несколько раз быстрее поиска по мэп такого же размера, без учёта накладных расходов на вставку. Опять же это речь про оптимизации - сделай сначала простой вариант и рабочую модель планировщика. Там нарисуется интерфейс для задач и их композиций.

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

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

классификации задач и построение дерева их очередей

Да, походу намечается именно это.

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

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

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

спроектировать систему без лишних аллокаций, но это будет стоить минимум на порядок дороже

Вот я и на распутье: аллочить на каждый чих наново или только в случае если свободных нет.

чем данные отличаются от таска

Тем что данных одна копия, а тасков, обслуживающих свой кусок данных — много.

как ты запустишь несколько задач одного типа параллельно

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

сделай сначала простой вариант

Вот так и поступлю скорее всего. Поэтапно буду решать.

Вот для варианта «на каждый чих» лочить стейты не надо, т.к. факт создания таска уже означает что он занят, а факт удаления, что свободен, настолько свободен, что его даже уже и нет. Но возникает вопрос: когда их удалять? Они ж могут ещё ждать сабтасков. Удалять всегда и сразу, а некоторое промежуточное недозавершенное состояние хранить не в тасках, а в данных, которые эти таски лопатят? И каллбеки тоже?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от crutch_master

Запили всё на rabbitmq и пистончике

гыы ))

Ты пошто Царю перечить удумал? Хочешь чтобы тебя на ноль умножили?

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Запили всё на rabbitmq и пистончике

Запили всё на ZMQ и плюсах!

pon4ik ★★★★★
()
Ответ на: комментарий от deep-purple

Тем что данных одна копия, а тасков, обслуживающих свой кусок данных — много.

Звучит странно, может быть тип таки один а копий данных много?

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Эммм... Кусков данных, одинаковых по типу (но разных по значениям и содержанию) много, а копия всей этой кучи данных одна. Тасков, одного типа некоторое кол-во, определяется динамически, например, если за один раз потребовалось пропахать (изменить, добавить, вынуть, вставить) несколько кусков данных какого-то типа, которые умеет лопатить соответствующего типа таск. Делать по таску на каждый целевой кусок данных — распухнет, т.к. данных много, а изменения могут затронуть и менее 1% данных.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

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

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

Ракетная наука… Это стейт задачи как сущности, я имел в виду прикладной стейт - его локов на длительное время необходимо избегать.

Но возникает вопрос: когда их удалять?

На этот вопрос отвечает shared политика хранения и подсчёт ссылок. Задача может пропасть из очереди, но пока её результаты кому-то нужны она будет жить.

Вот я и на распутье: аллочить на каждый чих наново или только в случае если свободных нет.

Аллочить на каждый чих пока профайлер не покажет тебе что так делать низзя.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

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

А меня беспокоит именно стейт тасков, а тот стейт не беспокоит. По крайней мере пока.

shared политика хранения и подсчёт ссылок

Что будет если когда новый подписант с калбеком придет перед самым завершением таска и попытается (без локов) подписаться на завершение того, что успело удалиться?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

Не будут если не будет вещей типа инверсий приоритетов и прочих архитектурных косяков.

Будут и ещё как, потоки могут виснуть, то и дело ожидая друг друга

Разумеется при условии, что задача очень короткая

при большом количестве коротких задач операции создания/завершения потока будут в сумме дорого стоить

или использует копию своего стейта.

тут вообще синхронизация не нужна посреди выполнения

next_time ★★★★★
()
Ответ на: комментарий от next_time

потоки могут виснуть, то и дело ожидая друг друга

Нет, в моем случае таск, запустивший сабтаск, подписывается на завершение сабтаска и завершается со статусом «ожидаю сабтаск». Так поток в пуле освобождается. А этот таск будет вызван из потока сабтаска, т.е. максимум что может произойти — очередь коллбеков родительских тасков вызываемых из сабтасков будет сидеть в одном треде пока не распутается до верха.

дорого

Да, поэтому надо будет каждый таск писать вдумчиво.

синхронизация не нужна посреди выполнения

Да. Почти. По возможности, короче.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от crutch_master

rabbitmq, zeromq, система сообщений qt... - готовых реализаций паттерна «очередь сообщений» сотни и использование одной из них - идея хорошая, только причём тут питон?

next_time ★★★★★
()
Ответ на: комментарий от deep-purple

Что будет если когда новый подписант с калбеком придет перед самым завершением таска и попытается (без локов) подписаться на завершение того, что успело удалиться?

У него либо есть ссылка на то, на что он хочет подписаться, либо нет…

Если ссылка есть, то задача не удалится.

Почему без локов? Как ты себе это представляешь? Ну разве что локфри список какой нить заводить, но это 100% оверкилл.

pon4ik ★★★★★
()
Ответ на: комментарий от next_time

Будут и ещё как, потоки могут виснуть, то и дело ожидая друг друга

Зачем?

при большом количестве коротких задач операции создания/завершения потока будут в сумме дорого стоить

Сорри, дальше не читал, освой тредпул :)

pon4ik ★★★★★
()
Ответ на: комментарий от deep-purple

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

next_time ★★★★★
()
Ответ на: комментарий от pon4ik

Зачем?

затем, что будут ждать освобождения очередного мутекса

Сорри, дальше не читал, освой тредпул :)

я подумал, что это вы его не осилили, сорян

next_time ★★★★★
()
Ответ на: комментарий от pon4ik

У него либо есть ссылка на то, на что он хочет подписаться, либо нет

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

Ну вот, значит локи у тасков быть должны: для подписки каллбеков и для установки стейтов.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

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

...это если готовое решение не брать

next_time ★★★★★
()
Ответ на: комментарий от pon4ik

операции создания/завершения потока

А я прочитал не потока, а таска.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Ещё раз, медленно.

Если

таск

кому то нужен

значит

где то помимо очереди

хранится

ссылка

на этот таск.

pon4ik ★★★★★
()
Ответ на: комментарий от next_time

затем, что будут ждать освобождения очередного мутекса

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

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

локфри

Оно нужно чуть чаще, чем никогда. В задаче ТС-а точно нет. Или под оверкилом ты имел ввиду производительность, а не ресурсы на реализацию?

anonymous
()
Ответ на: комментарий от anonymous

Зришь в корень - нужно когда планируешь сотни наносекунд отыгрыавать, ну максиум микросекунды при этом поток задач в пиках супер непрерывный.

При этом локфри сам по себе такое по пользе для производительности системы в целом, пока оно не вэйтфри.

А уж сексу и костылей на порядок больше.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

А, тогда ok. Неверно понял сначала

anonymous
()

Можно не делать таски совсем и просто передавать в замыкание данные по значению или по weak поинтеру.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

До тех пор, пока у тебя нет приоритетов и прочей политики планирования - можно. Хотя у ТС скорее всего и нет. Более того, можно ещё и корутинами обмазаться по факту. А если совсем подумать - то и в корутинах можно сменить механизм планирования но «стандартные» фреймворки придётся слегка пропатчить.

pon4ik ★★★★★
()
Ответ на: комментарий от deep-purple

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

какое последовательное выполнение, ты що?

Анон там много пурги пронёс, но. Про очереди он прав и всё что я говорил выше подразумевает что у тебя будет классический тредпул который вращает цикл обработки событий построенный на очереди или очереди с приоритетами.

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

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

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

Kuzy ★★★
()
Последнее исправление: Kuzy (всего исправлений: 2)
Ответ на: комментарий от Kuzy

Как то пока эта мысль на заходит. У тебя всё равно есть поток, который занимается планированием. При этом со стейтом и глобальным локом. Зачем две сущности с глобальным локом и стейтом вместо одной (очереди) - для меня загадка. Разве что код может получиться чуть по приятней и то не факт, лично я не полез бы искать планирование где то сбоку от разбора очереди задач.

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

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Я не очень понимаю, как можно обойтись одной очередью.

Вот в разных местах программы возникают задачи которые нужно выполнять асинхронно. Некоторые из них CPU bound их нужно отсылать в один тредпул. Некоторые IO bound их нужно отсылать в другой тердпул (из одного треда, скорее всего, да). Некоторые зависят от либы/кода не умеющей в мультитрединг (почти любой рендринг), их нужно отсылать в этот тред. Для этого нужно уже три очереди. Фьючеры нужны чтобы рулить очередностью. Загрузил картинку через IO -> как-нибудь обработал через CPU -> показал юзеру через main тред. С фьючерами это будет выглядеть как цепочка then.

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

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Я не очень понимаю, как можно обойтись одной очередью.

По одной очереди на пул. Пул планирует свои задачи сам в рамках приоритета. Если глянуть как это делает ОСь, примерно так там и происходит, есть i/o планировщик, есть планировщик процессов, есть механизм дождаться окончания задачи по таймауту.

С фьючерами это будет выглядеть как цепочка then.

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

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

Ну тогда у тебя получится отдельная сущность, при этом с довольно сложной логикой т.к. ей надо будет планировать для N пулов, и при за неё будут драться все участники забега. На практике я такого не видел, сам сделать тоже не пробовал, х3 возможно есть способы реализовать это так же эффективно.

pon4ik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.