Я пытаюсь создать службу, которая содержит множество клиентских и серверных сокетов (серверная служба, а также клиенты, которые подключаются к управляемым компонентам и сохраняются), которые синхронно опрошены через IO::Select
. Идея заключалась в том, чтобы обрабатывать потребности обработки ввода-вывода и/или запроса, которые возникают через пулы рабочих потоков.Неблокирующие операции ввода/вывода в Perl ограничены одним потоком? Хороший дизайн?
Ключевое слово shared
, которое обеспечивает совместное использование данных по потокам в Perl (threads::shared
), имеет свои пределы - ссылки на дескрипторы не входят в число примитивов, которые могут использоваться совместно.
Прежде чем я понял, что ручки и/или обрабатывать ссылки не могут быть разделены, план должен был иметь select()
нить, которая ухаживает опроса, а затем помещает соответствующие ручки в определенном ThreadQueue
ы распространяться через пул потоков для на самом деле делать чтение и письмо. (Я, конечно же, проектировал это так, чтобы модификация фактических наборов дескрипторов, используемых select
, была бы потокобезопасной и выполнялась только в одном потоке - то же самое, что работает select()
, и поэтому никогда, пока она работает, очевидно.)
Это не похоже, что это произойдет сейчас, потому что сами ручки не могут быть разделены, поэтому опрос, а также чтение и письмо должны произойти из одного потока. Есть ли обходной путь для этого? Я имею в виду разложение фактических системных вызовов по потокам; Очевидно, существуют способы использования очередей и буферов для получения данных, созданных в других потоках и фактически отправленных в других.
Одна из проблем, возникающих из-за этой ситуации, заключается в том, что я должен дать тайм-ауту select()
и ожидать, что он будет достаточно высоким, чтобы не вызывать каких-либо проблем с опросом довольно большого набора дескрипторов, хотя достаточно низко, чтобы не вводить слишком много задержек в моем цикле событий синхронизации - хотя, я понимаю, что если в процессе опроса обнаружено фактическое членство в модуле ввода-вывода, select()
вернется рано, что частично смягчит проблему. Я бы предпочел иметь какой-то способ пробуждения select()
от другого потока, но поскольку ручки не могут быть разделены, я не могу легко думать о способе этого делать и не видеть значения при этом; что другой поток будет знать о том, когда уместно просыпаться select()
в любом случае?
Если нет обходного пути, что такое хороший шаблон проектирования для этого типа услуг в Perl? У меня есть требование для довольно высокого уровня масштабируемости и параллельного ввода-вывода, и по этой причине вышли неблокирующий маршрут, а не просто порождали потоки для каждого прослушивающего сокета и/или клиентского и/или серверного процессов, так как многие люди, которые в наши дни не имеют отношения к сокетам - это, похоже, стандартная практика на Java-землях, и никто, кажется, не заботится о java.nio.*
за пределами узкой сферы системно-ориентированного программирования. Возможно, это просто мое впечатление. Во всяком случае, я не хочу так поступать.
Итак, с точки зрения опытного программиста систем Perl, как организовать этот материал? Монолитные потоки ввода-вывода + потоки чистого рабочего (не-ввода-вывода) + множество очередей? Какой-то умный хак? Любая безопасность нитей требует, чтобы смотреть за пределы того, что я уже перечислил? Есть ли способ лучше? У меня есть большой опыт архивирования такого рода программ на C, но не с идиомами Perl или характеристиками времени исполнения.
EDIT: P.S. Мне определенно пришло в голову, что, возможно, программа с этими требованиями к производительности, и этот дизайн просто не должен быть написан на Perl. Но я вижу в Perl очень много очень сложных сервисов, поэтому я не уверен в этом.
Интересные предложения. Мне особенно нравится подход к отправке базового FD и последующее построение дескриптора. Можете ли вы предложить способ инициализации дескриптора файла, а затем назначить его IO :: Socket позже, внутри потока? Я бы предпочел не создавать сокеты в одном потоке, а затем манипулировать ими в другом; возможно ли сделать что-то общее, например IO :: Handle-> new? –
Alex, без псевдокода, я не уверен, что понимаю подробности вашего вопроса здесь. Однако «использовать IO :: Socket :: INET» и «IO :: Socket :: INET-> new_from_fd ($ my_duplicated_fd,« r + »)» вы получите объект IO :: Socket. – pilcrow
О, я не знал, что IO :: Socket :: INET является подклассом IO :: Handle. Имеет смысл. –