Worker (file manager)
Worker — файловый менеджер для Linux и других UNIX-подобных операционных систем. Написан на С++ с использованием только стандартной X11-библиотеки xlib и библиотеки avfs для работы с виртуальной файловой системой, используемой при работе с архивами и доступом по ftp. В сравнении с другими файловыми менеджерами worker отличается высокой скоростью работы и нетребовательностью к ресурсам. Worker поддерживает создание вкладок (табов), работу с архивами, возможность прямого обращения к ftp-сайтам, UTF8, создание закладок, историю посещений и быстрый доступ, монтирование устройств, метки для файлов и групп файлов, цветовое выделение групп файлов, поиск файлов и по содержимому файлов, гибкую привязку команд к горячим клавишам. Управление файловым менеджером осуществляется через настраиваемое контекстное меню и посредством многочисленных настраиваемых кнопок, расположенных в нижней части рабочего окна приложения. Каждая кнопка вызывает отдельную функцию, возможно назначение разных функций для правой и левой кнопки мыши для каждой кнопки, для каждой из которых возможно задание горячей клавиши. В качестве функций могут выступать как встроенные инструменты Worker, так и любые внешние программы. Любая сторонняя программа легко интегрируется с помощью кнопок или горячих клавиш. Возможно создание групп кнопок, переключение между которыми осуществляется щелчком мышью по строке статуса. Worker полностью настраивается через графический интерфейс, в то же время сохраняя возможность ручной настройки посредством правки конфигурационных файлов без необходимости перезапуска Worker. Worker определяет тип файлов либо по их содержимому либо по расширению. Возможно задание своих масок содержимого файлов. В Worker реализована поддержка xft и libmagic. Программа переведена на многие языки, в том числе и на русский.
См. также
Ссылки
Wikimedia Foundation . 2010 .
Сравнение файловых менеджеров — В следующих таблицах сравнивается общая и техническая информация о множестве известных файловых менеджеров. Содержание 1 Общая информация 1.1 Кроссплатформенные файловые менеджеры … Википедия
Файловый менеджер — У этого термина существуют и другие значения, см. Менеджер (значения). Файловый менеджер (англ. file manager) компьютерная программа, предоставляющая интерфейс пользователя для работы с файловой системой и файлами. Файловый менеджер… … Википедия
Administrador de archivos — Un administrador de archivos, gestor de archivos o explorador de archivos (del inglés file manager) es una aplicación informática que provee acceso a archivos y facilita el realizar operaciones con ellos, como copiar, mover o eliminar archivos… … Wikipedia Español
List of Russian people — The Millennium of Russia monument in Veliky Novgorod, featuring the statues and reliefs of the most celebrated people in the first 1000 years of Russian history … Wikipedia
clerk — I (New American Roget s College Thesaurus) n. salesperson, man, or woman; registrar, scribe, secretary; copyist, writer. See writing, accounting, auxiliary. II (Roget s IV) n. 1. [A person engaged in selling] Syn. salesclerk, salesperson,… … English dictionary for students
Tea Party movement — This article is about the movement. For the protest events themselves, see Tea Party protests. For the U.S. Congressional caucus, see Tea Party Caucus … Wikipedia
Frederick D. Gregory — Infobox Astronaut name =Frederick Drew Gregory type =Astronaut status = Retired nationality =American date birth =Birth date and age|1941|1|7 place birth =Washington, D.C. occupation =Test Pilot rank =Colonel, USAF selection =1978 NASA Group time … Wikipedia
Murder of Victoria Climbié — Victoria Climbié Born 2 November 1991 (1991 11 02) Abobo, Ivory Coast Died 25 February 2000(2000 02 25) (aged 8) London, England, United Kingdom Cause of death … Wikipedia
performing arts — arts or skills that require public performance, as acting, singing, or dancing. [1945 50] * * * ▪ 2009 Introduction Music Classical. The last vestiges of the Cold War seemed to thaw for a moment on Feb. 26, 2008, when the unfamiliar strains … Universalium
Источник
Запуск worker’ов сервиса с помощью systemd
После выхода Ubuntu 16.04 (новый LTS релиз), systemd стал реальностью всех основных дистрибутивов Linux, использующихся на серверах. Это означает, что можно закладываться на расширенные возможности systemd, не рискуя оставить часть пользователей приложения «за бортом».
Этот пост о том, как реализовать многоворкерное приложение средствами systemd.
Abstract: Использование шаблонов сервисов и target’ов для запуска нескольких инстансов сервиса (реализация «воркеров»). Зависимость PartOf. Немного про [install] секцию у unit’ов.
Вступление
Многие языки программирования с плохой или никакой многопоточностью (Python, Ruby, PHP, довольно часто C/C++) используют концепцию «воркера». Вместо того, чтобы городить сложные отношения между тредами внутри приложения, они запускают несколько однопоточных копий приложения, каждое из которых берёт на себя кусок нагрузки. Благодаря опции SO_REUSEPORT есть даже возможность «вместе» слушать на одном и том же порту, что покрывает большинство задач, в которых возникает потребность в воркерах (собственно, обычные серверные приложения, реализующие API или обслуживающие веб-сайт).
Но такой подход требует наличия «супервизора», который отвечает за запуск копий, следит за их состоянием, обрабатывает ошибки, завершает при всякого рода stop/reload и т.д. При кажущейся тривиальности — это совершенно не тривиальная задача, полная нюансов (например, если один из воркеров попал в TASK_UNINTERRUPTIBLE или получил SIGSTOP, то могут возникнуть проблемы при restart у не очень хорошо написанного родителя).
Есть вариант запуска без супервизора, но в этом случае задача reload/restart перекладывается на администратора. При модели «один процесс на ядро» перезапуск сервиса на 24-ядерном сервере становится кандидатом в автоматизацию, которая в свою очередь требует обработки всех тех же самых SIGSTOP и прочих сложных нюансов.
Одним из вариантов решения проблемы является использование шаблонов сервисов systemd вместе с зависимостью от общего target’а.
Теория
Шаблоны
systemd поддерживает «шаблоны» для запуска сервисов. Эти шаблоны принимают параметр, который потом можно вставить в любое место в аргументах командной строки (man systemd.service). Параметр передаётся через символ ‘@’ в имени сервиса. Часть после ‘@’ (но до точки) называется ‘instance name’, кодируется %i или %I. Полный список параметров — www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers. Наличие ‘@’ в имени сервиса (перед точкой) указывает на то, что это шаблон.
Попробуем написать простейший template:
И запустим несколько таких:
Теперь мы хотим каким-то образом запускать всех их общим образом. Для этого существуют target’ы
Target’ы
Target — это такой юнит systemd, который ничего не делает, но может использоваться как элемент зависимостей (target может зависеть от нескольких сервисов, или сервисы могут зависеть от target’а, который так же зависит от сервисов).
target’ы имеют расширение .target.
Напишем наш простейший target:
vim /etc/systemd/system/foobar.target
(внимание на .service, оно обязательно!)
Про ‘Wants’ мы поговорим чуть ниже.
Теперь мы можем запускать все три foobar-worker одновременно:
systemctl start foobar.target
(внимание на target — в случае с .service его можно опускать, в случае с .target — нет).
В списке процессов появилось три sleep’а. К сожалению, если мы сделаем systemctl stop foobar.target, то они не исчезнут, т.е. на «worker’ов» они мало похожи. Нам надо как-то объединить в единое целое target и worker’ов. Для этого мы будем использовать зависимости.
Зависимости
Systemd предоставляет обширнейший набор зависимостей, позволяющий описать что именно мы хотим. Нас из этого списка интересует ‘PartOf’. До этого мы использовали wants.
Сравним их поведение:
Wants (который мы использовали) — упомянутый сервис пытается стартовать, если основной юнит стартует. Если упомянутый сервис упал или не может стартовать, это не влияет на основной сервис. Если основной сервис выключается/перезапускается, то упомянутые в зависимости сервисы остаются незатронутыми.
PartOf — Если упомянутый выключается/перезапускается, то основной сервис так же выключется/перезапускается.
Как раз то, что нам надо.
Добавляем зависимость в описание воркера:
Всё. Если мы сделаем systemd stop foobar.target, то все наши воркеры остановятся.
Install-зависимости
Ещё одна интереснейшая фича systemd — install-зависимости. В sysv-init была возможность enable/disable сервисов, но там было очень трудно объяснить, как именно надо делать enable. На каких runlevel’ах? С какими зависимостями?
В systemd всё просто. Когда мы используем команду ‘enable’, то сервис «добавляется» (через механизм slice’ов) в зависимость к тому, что мы указали в секции [install]. Для нашего удобства есть зависимость WantedBy, которая по смыслу обратная к Wanted.
Есть куча стандартных target’ов, к которым мы можем цепляться. Вот некоторые из них (все — man systemd.special):
* multi-user.target (стандартное для «надо запуститься», эквивалент финального runlevel’а для sysv-init).
* default.target — алиас на multi-user
* graphical.target — момент запуска X’ов
Давайте прицепимся к multi-user.target.
Новое содержимое foobar.target:
Теперь, если мы его сделаем enable:
Всё, наш сервис, слепленный из нескольких worker’ов готов запуску/перезапуску как единое целое, плюс его будут запускать при старте нашего компьютера/сервера.
Источник
Многозадачность в ядре Linux: workqueue
Продолжаем тему многопоточности в ядре Linux. В прошлый раз я рассказывала про прерывания, их обработку и tasklet’ы, и так как изначально предполагалось, что это будет одна статья, в своем рассказе о workqueue я буду ссылаться на tasklet’ы, считая, что читатель уже с ними знаком.
Как и в прошлый раз, я постараюсь сделать мой рассказ максимально подробным и детальным.
Workqueue
Workqueue — это более сложные и тяжеловесные сущности, чем tasklet’ы. Я даже не буду пытаться описать здесь все тонкости реализации, но самое важное, надеюсь, я разберу более или менее подробно.
Workqueue, как и tasklet’ы, служат для отложенной обработки прерываний (хотя их можно использовать и для других целей), но, в отличие от tasklet’ов, выполняются в контексте kernel-процесса, соответственно, они не обязаны быть атомарными и могут использовать функцию sleep(), различные средства синхронизации и т.п.
Давайте сначала разберемся, как в целом организован процесс обработки workqueue. На картинке он показан очень приближенно и упрощенно, как все происходит на самом деле, подробно описано ниже.
В этом темном деле замешаны несколько сущностей.
Во-первых, work item (для краткости просто work) — это структура, описывающая функцию (например, обработчик прерывания), которую мы хотим запланировать Его можно воспринимать как аналог структуры tasklet. Tasklet’ы при планировании добавлялись в очереди, скрытые от пользователя, теперь же нам нужно использовать специальную очередь — workqueue.
Tasklet’ы разгребаются функцией-планировщиком, а workqueue обрабатывается специальными потоками, которые зовутся worker’ами.
Worker’ы обеспечивают асинхронное исполнение work’ов из workqueue. Хотя они вызывают work’и в порядке очереди, в общем случае о строгом, последовательном выполнении речи не идет: все-таки здесь имеют место вытеснение, сон, ожидание и т.д.
Вообще, worker’ы — это kernel-потоки, то есть ими управляет основной планировщик ядра Linux. Но worker’ы частично вмешиваются в планирование для дополнительной организации параллельного исполнения work’ов. Про это подробнее пойдет ниже.
Чтобы очертить основные возможности механизма workqueue, я предлагаю изучить API.
Про очередь и ее создание
Параметры fmt и args — это printf-формат для имени и аргументы к нему. Параметр max_activate отвечает за максимальное число work’ов, которые из этой очереди могут исполняться параллельно на одном CPU.
Очередь можно создать со следующими флагами:
- WQ_HIGHPRI
- WQ_UNBOUND
- WQ_CPU_INTENSIVE
- WQ_FREEZABLE
- WQ_MEM_RECLAIM
Особое внимание следует уделить флагу WQ_UNBOUND. По наличию этого флага очереди делятся на привязанные и непривязанные.
В привязанных очередях work’и при добавлении привязываются к текущему CPU, то есть в таких очередях work’и исполняются на том ядре, которое его планирует. В этом плане привязанные очереди напоминают tasklet’ы.
В непривязанных очередях work’и могут исполняться на любом ядре.
Важным свойством реализации workqueue в ядре Linux является дополнительная организация параллельного исполнения, которая присутствует у привязанных очередей. Про нее подробнее написано ниже, сейчас скажу, что осуществляется таким образом, чтобы использовалось как можно меньше памяти, и чтобы при этом процессор не простаивал. Реализовано это все с предположением, что один work не использует слишком много тактов процессора.
Для непривязанных очередей такого нет. По сути, такие очереди просто предоставляют work’ам контекст и запускают их как можно раньше.
Таким образом, непривязанные очереди следует использовать, если ожидается интенсивная нагрузка на процессор, так как в таком случае планировщик позаботится о параллельном исполнении на нескольких ядрах.
По аналогии с tasklet’ами, work’ам можно присваивать приоритет исполнения, нормальный или высокий. Приоритет общий на всю очередь. По умолчанию очередь имеет нормальный приоритетом, а если задать флаг WQ_HIGHPRI, то, соответственно, высокий.
Флаг WQ_CPU_INTENSIVE имеет смысл только для привязанных очередей. Этот флаг — отказ от участия в дополнительной организации параллельного исполнения. Этот флаг следует использовать, когда ожидается, что work’и будут расходовать много процессорного времени, в этом случае лучше переложить ответственность на планировщик. Про это подробнее написано ниже.
Флаги WQ_FREEZABLE и WQ_MEM_RECLAIM специфичны и выходят за рамки темы, поэтому подробно на них останавливаться не будем.
Иногда есть смысл не создавать свои собственные очереди, а использовать общие. Основные из них:
- system_wq — привязанная очередь для быстрых work’ов
- system_long_wq — привязанная очередь для work’ов, которые предположительно будут исполняться долго
- system_unbound_wq — непривязанная очередь
Про work’и и их планирование
Теперь разберемся с work’ами. Сначала взглянем на макросы инициализации, декларации и подготовки:
В очереди work’и добавляются с помощью функций:
Вот на этом стоит остановиться поподробнее. Хотя мы в качестве параметра указываем очередь, на самом деле, work’и кладутся не в сами workqueue, как это может показаться, а в совершенно другую сущность — в список-очередь структуры worker_pool. Структура worker_pool, по сути, самая главная сущность в организации механизма workqueue, хотя для пользователя она остается за кулисами. Именно с ними работают worker’ы, и именно в них содержится вся основная информация.
Теперь посмотрим, какие пулы есть в системе.
Для начала пулы для привязанных очередей (на картинке). Для каждого CPU статически выделяются два worker pool: один для высокоприоритетных work’ов, другой — для work’ов с нормальным приоритетом. То есть, если ядра у нас четыре, то привязанных пулов будет всего восемь, не смотря на то, что workqueue может быть сколько угодно.
Когда мы создаем workqueue, у него для каждого CPU выделяется служебный pool_workqueue (pwq). Каждый такой pool_workqueue ассоциирован с worker pool, который выделен на том же CPU и соответствует по приоритету типу очереди. Через них workqueue взаимодействует с worker pool.
Worker’ы исполняют work’и из worker pool без разбора, не различая, к какому workqueue они принадлежали изначально.
Для непривязанных очередей worker pool’ы выделяются динамически. Все очереди можно разбить на классы эквивалентности по их параметрам, и для каждого такого класса создается свой worker pool. Доступ к ним осуществляется с помощью специальной хэш-таблицы, где ключом служит набор параметров, а значением, соответственно, worker pool.
На самом деле у непривязанных очередей все немножко сложнее: если у привязанных очередей создавались pwq и очереди для каждого CPU, то здесь они создаются для каждого узла NUMA, но это уже дополнительная оптимизация, которую в деталях рассматривать не будем.
Всякие мелочи
Еще приведу несколько функций из API для полноты картины, но подробно о них говорить не буду:
Как worker’ы справляются со своей работой
Теперь, как мы познакомились с API, давайте попробуем подробнее разобраться, как это все работает и управляется.
У каждого пула есть набор worker’ов, которые разгребают задачи. Причем, количество worker’ов меняется динамически, подстраиваясь под текущую ситуацию.
Как мы уже выяснили, worker’ы — это потоки, которые в контексте ядра выполняют work’и. Worker достает их по порядку один за другим из ассоциированного с ним worker pool, причем work’и, как мы уже знаем, могут принадлежать к разным исходным очередям.
Worker’ы условно могут находиться в трех логических состояниях: они могут быть простаивающими, запущенными или управляющими.
Worker может простаивать и ничего не делать. Это, например, когда все work’и уже исполняются. Когда worker переходит в это состояние, он засыпает и, соответственно, не будет исполняться до тех пор, пока его не разбудят;
Если не требуется управление пулом и список запланированных work’ов не пуст, то worker начинает исполнять их. Такие worker’ы условно будем называть запущенными.
Если же необходимо, worker берет на себя роль управляющего пулом. У пула может быть либо только один управляющий worker, либо не быть его вообще. Его задача — поддерживать оптимальное число worker’ов на пул. Как он это делает? Во-первых, удаляются worker’ы, которые достаточно долго простаивают. Во-вторых, создаются новые worker’ы, если выполняются сразу три условия:
- еще есть задачи на выполнение (work’и в пуле)
- нет простаивающих worker’ов
- нет работающих worker’ов (то есть активных и при этом не спящих)
Однако, в последнем условии есть свои нюансы. Если очереди пула непривязанные, то учет запущенных worker’ов не осуществляется, для них это условие всегда истинно. То же самое справедливо и в случае выполнения worker’ом задачи из привязанной, но с флагом WQ_CPU_INTENSIVE, очереди. При этом, в случае привязанных очередей, так как worker’ы работают с work’ами из общего пула (который один из двух на каждое ядро на картинке выше), то получается, что некоторые из них учитываются как работающие, а некоторые — нет. Из этого же следует, что выполнение work’ов из WQ_CPU_INTENSIVE очереди может начаться не сразу, зато сами они не мешают исполняться другим work’ам. Теперь должно быть понятно, почему это флаг так называется, и почему он используется, когда мы ожидаем, что work’и будут выполняться долго.
Учет работающих worker’ов осуществляется прямо из основного планировщика ядра Linux. Такой механизм управления обеспечивает оптимальный уровень параллельности (concurrency level), не давая workqueue создавать слишком много worker’ов, но и не заставляя work’и без нужды ждать слишком долго.
Те, кому интересно, могут посмотреть функцию worker’а в ядре, называется она worker_thread().
Со всеми описанными функциями и структурами можно подробнее ознакомиться в файлах include/linux/workqueue.h, kernel/workqueue.c и kernel/workqueue_internal.h. Также по workqueue есть документация в Documentation/workqueue.txt.
Еще стоит отметить, что механизм workqueue используется в ядре не только для отложенной обработки прерываний (хотя это довольно частый сценарий).
Таким образом, мы рассмотрели механизмы отложенной обработки прерываний в ядре Linux — tasklet и workqueue, которые представляют собой особую форму многозадачности. Про прерывания, tasklet’ы и workqueue можно почитать в книге «Linux Device Drivers» авторов Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini, правда, информация там временами устаревшая.
В комментарии Zyoma к статье про tasklet’ы также советуется «Ядро Linux. Описание процесса разработки» Р. Лава.
Источник