Вопрос больше философский, поэтому сильно не пинайте.
Хочется иметь гарантию, что процедуры завершения для какого-либо объекта, поддерживающего асинхронные операции, будут вызываться в одном и том же потоке.
Дабы избавиться от лишней синхронизации.
Например. Серверное приложение, зааксептили соединение от клиента, привязали его к какому-то потоку (к какому — неважно. например, к тому который сейчас меньше всего клиентов обслуживает). Затем, оповещения о всех наших асинхронных операциях на этом сокете приходят в этот поток. Т.е. сериализованы — синхронизация не нужна.
Далее, если для обслуживания этого клиента нам нужны еще какие-то асинхронные объекты (например файл, таймер, пайп — что угодно), мы всех их привязываем к потоку обслуживающему данного клиента. Таким образом, оповещения о завершении асинхронных операций на этих объектах, опять же приезжают в наш поток. Синхронизации не нужно. Код превращается в аккуратный
конечный автомат безо всяких лишних блокировок (если нужно шарить данные с другими сессиями — там блокироки нужны, если у нас таких потоков больше одного).
Т.е. получаем нечто вроде легких потоков.
В неуправляемом коде (или с использованием интеропа) делается просто — заводим N completion port-ов, N потоков, добавляем некий load-balancer и вуаля.
Есть ли идеи как это реализовать используя родные .NET классы и не городя кучу интеропа? Всем спасибо за идеи
Здравствуйте, jedi, Вы писали:
J>В неуправляемом коде (или с использованием интеропа) делается просто — заводим N completion port-ов, N потоков, добавляем некий load-balancer и вуаля.
Если я правильно понял Рихтера, то процедура завершения на completion port выполняется в контексте того потока, который completion port пожелает для этой цели употребить
But I/O completion ports are very smart. When a completion port wakes a thread, the completion port places the thread's ID in the fourth data structure associated with the completion port, a released thread list. (See Figure 2-1.) This allows the completion port to remember which threads it awakened and to monitor the execution of these threads. If a released thread calls any function that places the thread in a wait state, the completion port detects this and updates its internal data structures by moving the thread's ID from the released thread list to the paused thread list (the fifth and final data structure that is part of an I/O completion port).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, jedi, Вы писали:
J>>В неуправляемом коде (или с использованием интеропа) делается просто — заводим N completion port-ов, N потоков, добавляем некий load-balancer и вуаля.
PD>Если я правильно понял Рихтера, то процедура завершения на completion port выполняется в контексте того потока, который completion port пожелает для этой цели употребить
Спору нет. Но если у нас на каждом порту ждет ровно 1 поток, то и получается картина которую я описал.
В добавление. На том именно потоке, котррый был изначально выбран для этой цели, исполняются APC юзеровского режима. Вот QueuUserAPC приводит к постановке APC именно в очередь данного потока и никакого другого.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В добавление. На том именно потоке, котррый был изначально выбран для этой цели, исполняются APC юзеровского режима. Вот QueuUserAPC приводит к постановке APC именно в очередь данного потока и никакого другого.
Спасибо, я знаю. Вопрос не стоял как это сделать на WinAPI, я в курсе — делал и не раз. Если бы был не в курсе — спросил бы в профильном форуме.
Вопрос стоял в том, как масимально воспользоваться родными классами .NET
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>В добавление. На том именно потоке, котррый был изначально выбран для этой цели, исполняются APC юзеровского режима. Вот QueuUserAPC приводит к постановке APC именно в очередь данного потока и никакого другого.
J>Спасибо, я знаю. Вопрос не стоял как это сделать на WinAPI, я в курсе — делал и не раз. Если бы был не в курсе — спросил бы в профильном форуме. J>Вопрос стоял в том, как масимально воспользоваться родными классами .NET
Воспользуся CCR. Там уже готовая инфраструктура для этих целей.
Можешь еще на axum глянуть
Re[2]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 09:58
Оценка:
Здравствуйте, jedi, Вы писали:
J>В неуправляемом коде (или с использованием интеропа) делается просто — заводим N completion port-ов, N потоков, добавляем некий load-balancer и вуаля.
И на корню зарубаем важнейшую возможность порта — оптимизацию загрузки процессоров путём минимизации переключений контекстов потоков.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если я правильно понял Рихтера, то процедура завершения на completion port выполняется в контексте того потока, который completion port пожелает для этой цели употребить
Более того, порт выбирает для этого поток, последним вызвавший GetQueuedCompletionStatus, в надежде на то, что данный поток ещё не уснул, и не придётся тратить ресурсы на его пробуждение. И так и происходит, когда когда завершённых запросов в очереди порта больше, чем потоков.
В общем, сомнительное по части эффективности решение.
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, jedi, Вы писали:
J>>В неуправляемом коде (или с использованием интеропа) делается просто — заводим N completion port-ов, N потоков, добавляем некий load-balancer и вуаля.
А>И на корню зарубаем важнейшую возможность порта — оптимизацию загрузки процессоров путём минимизации переключений контекстов потоков.
Вы уверены что проигрыш в этом не компенсируется выигрышем от ненужности большинства блокировок (и вызванных ими сбросов кеша) + облегчением сопровождения кода?
Причем, часто и не нужно больше одного потока на сервер (если все операции асинхронные). Даже если сессии взаимодействуют между собой, можно разделить их на логические группы,
взаимодействие между которыми минимально.
А>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Если я правильно понял Рихтера, то процедура завершения на completion port выполняется в контексте того потока, который completion port пожелает для этой цели употребить
А>Более того, порт выбирает для этого поток, последним вызвавший GetQueuedCompletionStatus, в надежде на то, что данный поток ещё не уснул, и не придётся тратить ресурсы на его пробуждение. И так и происходит, когда когда завершённых запросов в очереди порта больше, чем потоков.
Я не вижу почему это не будет происходить и в моей схеме, в ситуации когда число потоков(портов) равно числу процессоров.
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[4]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 12:00
Оценка:
Здравствуйте, jedi, Вы писали:
J>Вы уверены что проигрыш в этом не компенсируется выигрышем от ненужности большинства блокировок (и вызванных ими сбросов кеша) + облегчением сопровождения кода?
Да, уверен. Минимизация блокировок, по моему мнению, должна обеспечиваться архитектурно, минимизирую вероятность пересечения потоков на разделяемых между ними ресурсах и сводя число таких ресурсов к минимому. А взаимосвязь блокировок и сбросов кэша я как-то не очень уловил. Если число конкурирующих потоков превышает число процессоров, то переключения процессара с потока на поток могут приводить к сбросу кэша даже при отсутствии блокировок. Не говоря уж о необходимости переключать контексты потоков, что само по себе обходится, как известно, весьма недёшево.
Конечно, при ттаком подходе требуется перестроить тип мышления, но тут уж ничего не поделаешь. Хотя всё равно остаётся всё тот-же конечный автомат, только уже "трёхмерный", а не "плоский"
J>Причем, часто и не нужно больше одного потока на сервер (если все операции асинхронные). Даже если сессии взаимодействуют между собой, можно разделить их на логические группы, J>взаимодействие между которыми минимально.
Для максимального использования ресурсов желательно иметь по одному активному потоку на процессор, это аксиома. При этом, если потоки могут периодически засыпать на каких-то синхронных операциях, то желательно иметь про запас еще по одному-два потока на процессор, чтобы процессоры не "простаивали" без дела.
А>>Более того, порт выбирает для этого поток, последним вызвавший GetQueuedCompletionStatus, в надежде на то, что данный поток ещё не уснул, и не придётся тратить ресурсы на его пробуждение. И так и происходит, когда когда завершённых запросов в очереди порта больше, чем потоков.
J>Я не вижу почему это не будет происходить и в моей схеме, в ситуации когда число потоков(портов) равно числу процессоров.
К сожалению, причины есть. Несколько экземпляров порта никак не взаимодействуют друг с другом. Каждый из них принимает решения самостоятельно, не советуясь с другими. В результате при N портах мы получаем по N активных потоков на каждый процессор. Да Вы проверьте сами, это легко выясняется с помощью простого теста, я в своё время именно так и поступил.
Здравствуйте, jedi, Вы писали:
J>Я не вижу почему это не будет происходить и в моей схеме, в ситуации когда число потоков(портов) равно числу процессоров.
Не будет, если при этом один поток на порт. Все верно ИМХО. Но в .Net предпочитают, видите ли ThreadPool, а для него
public static bool SetMaxThreads (
int workerThreads,
int completionPortThreads
)
You cannot set the number of worker threads or the number of I/O completion threads to a number smaller than the number of processors in the computer.
и получается, что в пуле не может быть один поток, а будет не менее, чем имеется процессоров...
А у класса Thread вроде как нет метода для работы с work item.
J>>Я не вижу почему это не будет происходить и в моей схеме, в ситуации когда число потоков(портов) равно числу процессоров.
А>К сожалению, причины есть. Несколько экземпляров порта никак не взаимодействуют друг с другом. Каждый из них принимает решения самостоятельно, не советуясь с другими. В результате при N портах мы получаем по N активных потоков на каждый процессор.
Так вроде автор предлагал один поток на порт. И будет N потоков на N портах, по потоку на процессор. Или я не так понял ?
JD>Но если у нас на каждом порту ждет ровно 1 поток
With best regards
Pavel Dvorkin
Re[5]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 12:05
Оценка:
А>К сожалению, причины есть. Несколько экземпляров порта никак не взаимодействуют друг с другом. Каждый из них принимает решения самостоятельно, не советуясь с другими. В результате при N портах мы получаем по N активных потоков на каждый процессор. Да Вы проверьте сами, это легко выясняется с помощью простого теста, я в своё время именно так и поступил.
Пардон, послидний абзац не относится к Вашему высказыванию. Виноват, проявил невнимательность при форматировании ответа
Да, в Вашей схеме это будет происходить так-же. Мои слова не относились напрямую к Вам, это было просто небольшое дополнение к высказыванию Pavel Dvorkin [01.07.09 15:53]
Re[6]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 12:20
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Так вроде автор предлагал один поток на порт. И будет N потоков на N портах, по потоку на процессор. Или я не так понял ?
JD>>Но если у нас на каждом порту ждет ровно 1 поток
Хм, а может это я всё неправильно понял? Я как-то не заметил указания, что N равно числу процессоров, и потому предположил что N из каких-то других соображений. Но даже если и так, то каждый экземпляр порта будет сам принимать решения, независимо от остальных экзэмпляров, и это неминуемо приведёт к дисбалансу, насколько я понимаю. Какие-то очереди будут обрабатываться быстрее остальных, и опустеют, когда в других ещё есть задания. В результате какой-то процессор окажется простаивающим, в то время как в других портах есть задания в очереди.
Здравствуйте, Аноним, Вы писали:
А>Хм, а может это я всё неправильно понял? Я как-то не заметил указания, что N равно числу процессоров, и потому предположил что N из каких-то других соображений. Но даже если и так, то каждый экземпляр порта будет сам принимать решения, независимо от остальных экзэмпляров, и это неминуемо приведёт к дисбалансу, насколько я понимаю. Какие-то очереди будут обрабатываться быстрее остальных, и опустеют, когда в других ещё есть задания. В результате какой-то процессор окажется простаивающим, в то время как в других портах есть задания в очереди.
Это я не понял. Предположим, мы имеем N портов и 1 поток на порту. Если бы было ровно наоборот, то PostQueuedCompletionStatus отправлялось бы в единственный порт, а уж он пусть выбирает поток. Но у нас N портов, так что выбор порта (==потока) будет делать некий иной код. Например, вести учет зантяых/свободных потоков и выбирать один из них. Так что будут задания в очередях или нет — зависит от того, как этот код работает. В сущности то, что предлагает jedi, есть просто ручное управление потоками. Я поэтому и предложил QuueUserAPC, там поток явно указывается.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, jedi, Вы писали:
J>>Я не вижу почему это не будет происходить и в моей схеме, в ситуации когда число потоков(портов) равно числу процессоров.
PD>Не будет, если при этом один поток на порт. Все верно ИМХО. Но в .Net предпочитают, видите ли ThreadPool, а для него
PD>public static bool SetMaxThreads ( PD> int workerThreads, PD> int completionPortThreads PD>) PD>You cannot set the number of worker threads or the number of I/O completion threads to a number smaller than the number of processors in the computer.
Угу, в этом и проблема. А еще, я не понимаю почему мне не дают создать свой ThreadPool и привязывать хендлы к нему.
PD>и получается, что в пуле не может быть один поток, а будет не менее, чем имеется процессоров... PD>А у класса Thread вроде как нет метода для работы с work item.
В общем, то что я хочу сэмулировать перекидывая все завершения в некий единый поток. Но это полная фигня, ибо убивает всю идею + куча лишней работы и синхронизации.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это я не понял. Предположим, мы имеем N портов и 1 поток на порту. Если бы было ровно наоборот, то PostQueuedCompletionStatus отправлялось бы в единственный порт, а уж он пусть выбирает поток. Но у нас N портов, так что выбор порта (==потока) будет делать некий иной код. Например, вести учет зантяых/свободных потоков и выбирать один из них. Так что будут задания в очередях или нет — зависит от того, как этот код работает. В сущности то, что предлагает jedi, есть просто ручное управление потоками.
То что я предлагаю называется по сути "green threads" (ну почти). Я просто думал есть способ соорудить это стандартным средствами .NET. А на нет и суда нет. Если припечет, будем смотреть сторонние решения. Пока данный вопрос для меня чисто философский (что я и написал в самом первом сообщении).
PD>Я поэтому и предложил QuueUserAPC, там поток явно указывается.
QueueUserAPC работает, проверено . К сожалению, насколько мне известно, в дотнет нет его поддержки (в первую очередь, нет способа сделать ReadFile который вернет результат через APC).
Если я не прав — поправьте.
В общем, резюме такое. Стандартными средствами сделать то, что я хочу нельзя. Ну и бог с ним
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[8]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 12:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это я не понял. Предположим, мы имеем N портов и 1 поток на порту. Если бы было ровно наоборот, то PostQueuedCompletionStatus отправлялось бы в единственный порт, а уж он пусть выбирает поток. Но у нас N портов, так что выбор порта (==потока) будет делать некий иной код. Например, вести учет зантяых/свободных потоков и выбирать один из них. Так что будут задания в очередях или нет — зависит от того, как этот код работает. В сущности то, что предлагает jedi, есть просто ручное управление потоками. Я поэтому и предложил QuueUserAPC, там поток явно указывается.
Но Вы же выбираете порт в момент создания девайса, верно? Как Вы можете заранее предсказать, с каим девайсом будет более "плотная" работа, а какой будет больше простаивать? Вот возьмём к примеру сокеты. Вам подключился клиент, Вы так или иначе получили экзэмпляр сокета и должны привязать его к определённому порту. Откуда Вы знаете, что данный клиент будет отправлять много запросов или наоборот, мало? Может он запросит у Вас 100 байт данных, которые лежат у Вас в кэше сервера, и задумается над ними часа на два. А потом проснётся и начнёт сыпать по 10 тяжёлых запросов каждую секунду. А ведь привязка может осуществляться вообще до подключения клиента, хоть тот-же AcceptEx взять, или именованные пайпы. Тогда вообще никаких шансов угадать.
По сути то, что Вы описываете, и есть функции порта, а Вы пытаетесь взять их на себя, но при этом обладете гораздо меньшими возможностями, чем порт. Возникает вопрос — зачем тогда порт? С тем-же успехом можно обойтись без него, вызывая в потоке WaitForMultipleObjects, это даже даст больше возможностей по управлению процессом.
Здравствуйте, jedi, Вы писали:
J>Угу, в этом и проблема. А еще, я не понимаю почему мне не дают создать свой ThreadPool и привязывать хендлы к нему.
Ну это-то понятно.
The thread pool is created the first time you call QueueUserWorkItem or BindIoCompletionCallback, or when a timer-queue timer or registered wait operation queues a callback function.
Нет в Windows создания этого самого пула. Создается он автоматом при условии выше. И один он на весб процесс. И привязывать к нему потоки нельзя. Он сам умный, он ими управляет как надо.
В Висте появились новые пулы (см. CreateThreadpool), но не могли же авторы .Net ограничиться Вистой.
With best regards
Pavel Dvorkin
Re[9]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 13:02
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Pavel Dvorkin, Вы писали:
М-да Как-бы воспринял Вас как автора поста Не обижайтесь, если что, просто пытаюсь одновременно заниматься тремя разными делами и при этом ещё пить пиво В общем, отнеситесь снисходительно к этой путанице
Здравствуйте, Аноним, Вы писали:
А>Но Вы же выбираете порт в момент создания девайса, верно? Как Вы можете заранее предсказать, с каим девайсом будет более "плотная" работа, а какой будет больше простаивать? Вот возьмём к примеру сокеты. Вам подключился клиент, Вы так или иначе получили экзэмпляр сокета и должны привязать его к определённому порту. Откуда Вы знаете, что данный клиент будет отправлять много запросов или наоборот, мало? Может он запросит у Вас 100 байт данных, которые лежат у Вас в кэше сервера, и задумается над ними часа на два. А потом проснётся и начнёт сыпать по 10 тяжёлых запросов каждую секунду. А ведь привязка может осуществляться вообще до подключения клиента, хоть тот-же AcceptEx взять, или именованные пайпы. Тогда вообще никаких шансов угадать.
А мне какое дело ? В момент привязки порт (==поток) помечается как занятый, и будет он таким, пока не отвяжется. А порты равноправны. Или Вы имеете в виду, что может быть много запросов до отвязки ? Тогда да. Но у меня был один. Впрочем, я порт не использовал, а просто QueueUserAPC. Схема простая — привязка потока при появлении запроса, отвязка при окончании обработки. В общем, посылка команд потоку, который спит в alertable состоянии. Ну а сколько времени он будет выполнять — сие от меня не зависит.
А>По сути то, что Вы описываете, и есть функции порта, а Вы пытаетесь взять их на себя, но при этом обладете гораздо меньшими возможностями, чем порт.
Верно.
>Возникает вопрос — зачем тогда порт?
См. исходный постинг jedi. Он в основном хотел избежать синхронизации.
>С тем-же успехом можно обойтись без него, вызывая в потоке WaitForMultipleObjects, это даже даст больше возможностей по управлению процессом.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Pavel Dvorkin, Вы писали:
А>М-да Как-бы воспринял Вас как автора поста Не обижайтесь, если что, просто пытаюсь одновременно заниматься тремя разными делами и при этом ещё пить пиво В общем, отнеситесь снисходительно к этой путанице
Здравствуйте, jedi, Вы писали:
J> А еще, я не понимаю почему мне не дают создать свой ThreadPool и привязывать хендлы к нему.
Может потому, xто слишком многие пытались использовать его не по назначению? Например, создавая по несколько экзэмпляров порта вместо одного, вот авторы NET и решили:"Да ну их всех нафиг, сами всё разрулим!"
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Это я не понял. Предположим, мы имеем N портов и 1 поток на порту. Если бы было ровно наоборот, то PostQueuedCompletionStatus отправлялось бы в единственный порт, а уж он пусть выбирает поток. Но у нас N портов, так что выбор порта (==потока) будет делать некий иной код. Например, вести учет зантяых/свободных потоков и выбирать один из них. Так что будут задания в очередях или нет — зависит от того, как этот код работает. В сущности то, что предлагает jedi, есть просто ручное управление потоками. Я поэтому и предложил QuueUserAPC, там поток явно указывается.
А>Но Вы же выбираете порт в момент создания девайса, верно? Как Вы можете заранее предсказать, с каим девайсом будет более "плотная" работа, а какой будет больше простаивать? Вот возьмём к примеру сокеты. Вам подключился клиент, Вы так или иначе получили экзэмпляр сокета и должны привязать его к определённому порту. Откуда Вы знаете, что данный клиент будет отправлять много запросов или наоборот, мало? Может он запросит у Вас 100 байт данных, которые лежат у Вас в кэше сервера, и задумается над ними часа на два. А потом проснётся и начнёт сыпать по 10 тяжёлых запросов каждую секунду. А ведь привязка может осуществляться вообще до подключения клиента, хоть тот-же AcceptEx взять, или именованные пайпы. Тогда вообще никаких шансов угадать.
Забудьте о втором порте и потоке. Он в другом процессе, на другой машине. Я просто хочу зеленые потоки
А>По сути то, что Вы описываете, и есть функции порта, а Вы пытаетесь взять их на себя, но при этом обладете гораздо меньшими возможностями, чем порт. Возникает вопрос — зачем тогда порт? С тем-же успехом можно обойтись без него, вызывая в потоке WaitForMultipleObjects, это даже даст больше возможностей по управлению процессом.
Ничего я не пытаюсь брать на себя. Порт — всего лишь способ асинхронного ввода-вывода. То что он берет на себя обязанности лоад-балансера когда потоков больше одного — хорошо. Но оно мне не надо.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, jedi, Вы писали:
J>>Угу, в этом и проблема. А еще, я не понимаю почему мне не дают создать свой ThreadPool и привязывать хендлы к нему.
PD>Ну это-то понятно.
PD>The thread pool is created the first time you call QueueUserWorkItem or BindIoCompletionCallback, or when a timer-queue timer or registered wait operation queues a callback function.
PD>Нет в Windows создания этого самого пула. Создается он автоматом при условии выше. И один он на весб процесс. И привязывать к нему потоки нельзя. Он сам умный, он ими управляет как надо.
PD>В Висте появились новые пулы (см. CreateThreadpool), но не могли же авторы .Net ограничиться Вистой.
Мне не нужен пул вообще, я просто хочу эффективный ввод-вывод в пределах одного потока без всяких синхронизаций. Если мне понадобится больше потоков — будет лоад балансер.
И не совсем обязательно этим потокам жить в одном процессе и на одной машине.
Ладно, дискуссия становится неинтересной. Мы уже выснили, что в .NET того что я хочу нет. А что и где есть — это тема для отдельной беседы.
Здравствуйте, jedi, Вы писали:
А>>По сути то, что Вы описываете, и есть функции порта, а Вы пытаетесь взять их на себя, но при этом обладете гораздо меньшими возможностями, чем порт. Возникает вопрос — зачем тогда порт? С тем-же успехом можно обойтись без него, вызывая в потоке WaitForMultipleObjects, это даже даст больше возможностей по управлению процессом.
J>Ничего я не пытаюсь брать на себя. Порт — всего лишь способ асинхронного ввода-вывода. То что он берет на себя обязанности лоад-балансера когда потоков больше одного — хорошо. Но оно мне не надо.
И еще. То что Вы рассказывает (да и сама идея тред пула) хорошо работает для серверов где клиенты независимы.
Теперь представьте себя что-то типа игрового сервера, где все взаимодействуют со всем. Все эти выгоды виндового тред пула мгновенно испарятся от офигительной тучи блокировок.
Ну и, я вас уверею, в более-менее нетривиальном сервере с fine-grained locks будет жить зоопарк багов синхронизации (видел своими глазами).
Так что, не надо мне лоад балансинга. Лоад балансинг есть свой. И клиенты будут раскидываться по серверам какими-то логическими группами. А будут эти сервера жить в одном процессе и разных потоках, в разных процессах и на разных машинах — это вообще неважно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[10]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 13:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>. Но у меня был один. Впрочем, я порт не использовал, а просто QueueUserAPC. Схема простая — привязка потока при появлении запроса, отвязка при окончании обработки. В общем, посылка команд потоку, который спит в alertable состоянии. Ну а сколько времени он будет выполнять — сие от меня не зависит.
Но это как-бы не совсем то, о чём писал автор темы. Автор хочет, чтобы все запросы одного клиента (в широком смысле ) шли в указанный им поток А у Вас привязка идёт на уровне запроса, и это, кстати, очень хорошо разруливается портом завершения. Вообще советую обратить на него внимание, если интересуетесь темой. Прирост производительности по сравнению с другими способами просто поразительный.
Да и, честно говоря, не особенно улавливаю, как предложенный автором темы способ может снизить требования к синхронизации. Как правило. в каждый конкретный момент времени и без того обрабатывается один запрос от конкретного клиента. То есть от одного клиента приходит один запрос и пока он не обработан, других запросов от этого клиента не посткпает. Либо, что реже, от клиента могут поступить сразу несколько запросов, но тогда эти запросы никак между собой не связаны. Как-то не улавливаю, где тут выигрыш в синхронизации от использования схемы "все запросы одного клиента в одном потоке". Впрочем, возможно просто сказывается привычка мыслить "параллельно"
Здравствуйте, <Аноним>, Вы писали:
А>Да и, честно говоря, не особенно улавливаю, как предложенный автором темы способ может снизить требования к синхронизации. Как правило. в каждый конкретный момент времени и без того обрабатывается один запрос от конкретного клиента. То есть от одного клиента приходит один запрос и пока он не обработан, других запросов от этого клиента не посткпает. Либо, что реже, от клиента могут поступить сразу несколько запросов, но тогда эти запросы никак между собой не связаны. Как-то не улавливаю, где тут выигрыш в синхронизации от использования схемы "все запросы одного клиента в одном потоке". Впрочем, возможно просто сказывается привычка мыслить "параллельно"
Вы исходите из предположения, что клиенты независимы. Это не всегда так. Не все сервера — это http сервера
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[11]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 13:50
Оценка:
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, jedi, Вы писали:
А>>>По сути то, что Вы описываете, и есть функции порта, а Вы пытаетесь взять их на себя, но при этом обладете гораздо меньшими возможностями, чем порт. Возникает вопрос — зачем тогда порт? С тем-же успехом можно обойтись без него, вызывая в потоке WaitForMultipleObjects, это даже даст больше возможностей по управлению процессом.
J>>Ничего я не пытаюсь брать на себя. Порт — всего лишь способ асинхронного ввода-вывода. То что он берет на себя обязанности лоад-балансера когда потоков больше одного — хорошо. Но оно мне не надо.
Пытаетесь — пытаетесь В такой схеме WaitForMultipleObjects даст куда большую управляемость, порт просто не нужен.
J>И еще. То что Вы рассказывает (да и сама идея тред пула) хорошо работает для серверов где клиенты независимы. J>Теперь представьте себя что-то типа игрового сервера, где все взаимодействуют со всем. Все эти выгоды виндового тред пула мгновенно испарятся от офигительной тучи блокировок. J>Ну и, я вас уверею, в более-менее нетривиальном сервере с fine-grained locks будет жить зоопарк багов синхронизации (видел своими глазами).
Ну и что Вы выиграете от того, что клиенты будут привязаны к конкретному потоку? Взаимодействие между клиентами всё равно придётся синхронизировать. А "зоопарк багов синхронизации" — это уже тема скорее для медицинского форума
Впрочем, коль Вам тема стала не интересна, то и продолжать нет смысла, мне она тем более ни к чему
Здравствуйте, <Аноним>, Вы писали:
А>Ну и что Вы выиграете от того, что клиенты будут привязаны к конкретному потоку? Взаимодействие между клиентами всё равно придётся синхронизировать. А "зоопарк багов синхронизации" — это уже тема скорее для медицинского форума
Еще раз. Поток один на всех. Зачем синхронизация?
А>Впрочем, коль Вам тема стала не интересна, то и продолжать нет смысла, мне она тем более ни к чему
Мне тема интересна. Но Ваш пойнт я понял — ничего делать не надо, все и так работает . Я вполне четко указал где это, мягко говоря, не так. Вы проигнорировали. О чем говорить-то?
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[13]: A-la легкие потоки
От:
Аноним
Дата:
01.07.09 14:13
Оценка:
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, <Аноним>, Вы писали:
А>>Ну и что Вы выиграете от того, что клиенты будут привязаны к конкретному потоку? Взаимодействие между клиентами всё равно придётся синхронизировать. А "зоопарк багов синхронизации" — это уже тема скорее для медицинского форума
J>Еще раз. Поток один на всех. Зачем синхронизация?
Действительно, незачем. Но тогда и всё остальное ни к чему. Зачем N портов, если поток один на всех? Вот только с масштабируемостью в такой схеме совсем худо. А если потоков всё-таки больше, чем один, то обязательно окажется, что два желающих взаимодействовать клиента "сидят" на разных потоках.
А>>Впрочем, коль Вам тема стала не интересна, то и продолжать нет смысла, мне она тем более ни к чему
J>Мне тема интересна. Но Ваш пойнт я понял — ничего делать не надо, все и так работает . Я вполне четко указал где это, мягко говоря, не так. Вы проигнорировали. О чем говорить-то?
Честно говоря, я не очень понимаю, из чего Вы вывели, будто я сказал "ничего делать не надо, все и так работает". Ещё меньше понимаю, где Вы "четко указал где это, мягко говоря, не так" Но говорить, судя по всему, действительно больше не о чем.