Варианты использования ithreads (потоков интерпретатора) в Perl и обоснование их использования или неиспользования? - PullRequest
30 голосов
/ 02 апреля 2012

Если вы хотите узнать , как использовать потоки интерпретатора Perl, есть хорошая документация в perlthrtut (учебник по потокам) и на странице управления threads pragma .Определенно достаточно написать несколько простых сценариев.

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

Эти темы доступны, когда perl -V:useithreads равен useithreads='define'; и развязан use threadsтакже называются ithreads и, возможно, более уместно, поскольку они сильно отличаются от потоков, предлагаемых операционными системами Linux или Windows или виртуальной машиной Java, в которых ничто не используется по умолчанию и вместо большого количества данныхкопируется не только стек потоков, что значительно увеличивает размер процесса.(Чтобы увидеть эффект, загрузите некоторые модули в тестовом скрипте, затем создайте потоки в цикле, приостанавливая нажатие клавиш каждый раз, и наблюдайте за увеличением памяти в диспетчере задач или top.)

[...] каждый раз, когда вы запускаете поток, все структуры данных копируются в новый поток.И когда я говорю все, я имею в виду все.Это, например, включает в себя тайники пакетов, глобальные переменные, лексические выражения в области видимости.Всё!

- Вещи, которые вам необходимо знать перед программированием Perl ithreads (Perlmonks 2003)

При исследовании темы Perl ithreads вы увидителюди, отговаривающие вас от их использования ( «крайне плохая идея», «принципиально некорректный» или «никогда не используют ithreads для чего-либо» ).

В учебнике по потокам Perl подчеркивается, что «потоки Perl различны» , но не слишком сложно объяснить, чем они отличаются и что это значит для пользователя.

Полезное, но очень краткое объяснение того, чтоНа самом деле это из справочной страницы Coro под заголовком ЭМУЛЯЦИЯ ПРОЦЕССА WINDOWS .Автор этого модуля ( Coro - единственные реальные потоки в Perl ) также не рекомендует использовать потоки интерпретатора Perl.

Где-то я читал, что компиляция perl с включенными потоками приведет к значительно более медленному интерпретатору.

Есть страница Perlmonks с 2003 года ( Вещи, которые вам нужно знать перед программированием Perl ithreads ), на которой автор спрашивает: «Теперь вы можете удивиться, почему Perl ithreads не использовал fork()? Разве это не имело бы больше смысла? "Это, кажется, было написано автором forks прагмы.Не уверен, что информация, приведенная на этой странице, все еще остается верной в 2012 году для более новых Perls.

Вот некоторые рекомендации по использованию потоков в Perl, которые я извлек из своих чтений (возможно, ошибочно):

Пока мои исследования.Теперь спасибо за больше света, который вы можете пролить на этот вопрос о потоках в Perl.Каковы некоторые разумные варианты использования ithreads в Perl?Каково обоснование их использования или неиспользования?

Ответы [ 2 ]

22 голосов
/ 03 апреля 2012

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

Вы можете безопасно использовать Perl ithreads, рассматривая их как независимых актеров .

  1. Создать поток :: Queue :: Any для "работы".
  2. Запуск нескольких ithreads и очередей «result», передавая им очереди («work» + own «result») по закрытию.
  3. Загрузка (требуется) всего остального кода, необходимого для вашего приложения (не перед потоками!)
  4. Добавьте работу для потоков в очередь по мере необходимости.

В "рабочий" пишет:

  1. Введите любой общий код (для любой работы)
  2. Блокировка-удаление части работы из очереди
  3. Загрузка по требованию любых других зависимостей, необходимых для этой части работы.
  4. Сделай работу.
  5. Передать результат обратно в главный поток через очередь "result".
  6. Вернуться к 2.

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

Каковы основные проблемы с Perl ithreads?

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

Вам нужно следить за поведением объектов с помощью методов DESTROY, когда они выходят из области видимости в одном потоке (если они все еще требуются в другом!)

Большой : Данные / переменные, которые не являются явно общими, CLONED в новые потоки. Это удар по производительности и, вероятно, совсем не то, что вы хотели. Обходной путь состоит в том, чтобы запустить ithreads из довольно «нетронутого» состояния (загружено не так много модулей).

IIRC, в пространстве имен Threads :: есть модули, которые помогают сделать явные зависимости и / или очистить клонированные данные для новых потоков.

Кроме того, в IIRC есть немного другая модель, использующая нити, называемые потоками «Квартира», реализованные Thread :: Appartment, которая имеет другой шаблон использования и другой набор компромиссов.

Результат:

Не используйте их, если не знаете, что делаете: -)

Fork может быть более эффективным в Unix, но история IPC намного проще для ithreads. (Это могло быть смягчено модулями CPAN с тех пор, как я в последний раз смотрел: -)

Они все еще лучше, чем потоки Python.

В один прекрасный день может быть что-то намного лучше в Perl 6.

8 голосов
/ 08 декабря 2012

Я несколько раз использовал "потоки" perl. Они наиболее полезны для запуска какого-либо процесса и продолжения чего-то другого. У меня нет большого опыта в теории того, как они работают под капотом, но у меня есть большой практический опыт программирования с ними.

Например, у меня есть серверный поток, который прослушивает входящие сетевые соединения и выдает ответ о состоянии, когда кто-то просит об этом. Я создаю этот поток, затем продолжаю и создаю другой поток, который контролирует систему, проверяет пять элементов, спит несколько секунд и снова зацикливается. Сбор данных монитора может занять 3-4 секунды, затем он помещается в общую переменную, и серверный поток может прочитать это при необходимости и сразу же вернуть последний известный результат тому, кто запросит. Поток монитора, когда обнаруживает, что элемент находится в плохом состоянии, запускает отдельный поток для восстановления этого элемента. Затем он движется дальше, проверяя другие элементы, пока ремонтируется плохой, и отбрасывая другие потоки на наличие других плохих элементов или присоединяясь к законченным ремонтным нитям. Основная программа все время зацикливается каждые несколько секунд, следя за тем, чтобы потоки монитора и сервера не были присоединены / работали. Все это может быть написано как группа отдельных программ, использующих какую-то другую форму IPC, но потоки perl делают это простым.

Другое место, где я их использовал, - это генератор фракталов. Я разделил бы части изображения, используя некоторый алгоритм, и затем запустил бы столько потоков, сколько у меня есть процессоров для выполнения работы. Каждый из них складывал свои результаты в один объект GD, что не вызывало проблем, поскольку каждый из них работал над разными частями массива, а затем, когда все было готово, я выписывал изображение GD. Это было мое введение в использование потоков perl, и это было хорошее введение, но затем я переписал его на C, и это было на два порядка быстрее :-). Затем я переписал свою версию на Perl с использованием Inline :: C, и она была только на 20% медленнее, чем версия на чистом C. Тем не менее, в большинстве случаев, когда вы хотите использовать потоки из-за нагрузки на процессор, вам, вероятно, нужно просто выбрать другой язык.

Как уже упоминалось, ветвь и нити действительно перекрываются для многих целей. Однако Coro на самом деле не допускает многопроцессорное использование или параллельную обработку, как это делают ветвь и нить, вы будете когда-либо видеть свой процесс только на 100%. Я слишком упрощаю это, но я думаю, что самый простой способ описать Coro - это планировщик для ваших подпрограмм. Если у вас есть подпрограмма, которая блокирует, вы можете переходить к другому и делать что-то еще, пока вы ждете, например, у вас есть приложение, которое вычисляет результаты и записывает их в файл. Один блок может вычислить результаты и вставить их в канал. Когда работа заканчивается, другой блок начинает записывать их на диск. Пока этот блок ожидает на диске, другой блок может снова начать вычислять результаты, если он получит больше работы. По общему признанию я не сделал много с Коро; это звучит как хороший способ ускорить некоторые вещи, но я немного расстроен тем, что не могу сделать две вещи одновременно.

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

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