Что такое пул в компьютере
Пул потоков — это коллекция рабочих потоков, которые эффективно выполняют асинхронные обратные вызовы от имени приложения. Пул потоков в основном используется для сокращения числа потоков приложения и обеспечения управления рабочими потоками. Приложения могут ставить в очередь рабочие элементы, связывать работу с ожидающими дескрипторами, автоматически ставить в очередь на основе таймера и выполнять привязку с помощью операций ввода-вывода.
6. Удаление дискового пространства
Если в дисковом пространстве больше нет надобности, его можно удалить.
Но чтобы носители были доступны для формирования структуры разделов и использования в отдельности, необходимо удалить и сам пул, как рассматривалось выше.
2. Пул носителей
Пул носителей – это точка сборки жёстких дисков, создание и настройка непосредственно самого массива (вне зависимости от его функциональности) . В пул не может быть добавлен SSD или HDD , на котором установлена текущая Windows. Для старта использования дисковых пространств потребуется как минимум один пустой (или с ненужными данными) жёсткий диск. Но, безусловно, лучше, чтобы их было как минимум два, так сразу можно будет оценить выгоды работы с массивом. С создания пула, собственно, и начинается работа с этой технологией. Жмём кнопку его создания.
Увидим все подключённые к компьютеру устройства информации, которые могут быть добавлены в пул. Они пустые неотформатированные и отформатированные будут отдельно распределены по соответствующим разделам. Здесь можем снять галочки с устройств, которые мы не собираемся использовать для массива. Затем жмём «Создать пул». Напомним, диски с имеющейся информацией впоследствии потеряют её.
Далее автоматом запустится создание дискового пространства. Но мы можем нажать кнопку отмены и немного разобраться с управлением пула. После того, как мы его создали, он будет отображаться в главном окне технологии. Здесь увидим справочную информацию об общем и по факту задействованном объёме, информацию о носителях пула, сможем в будущем удалять их и добавлять новые, переименовывать для удобства восприятия. Ну и при необходимости сможем удалить сам пул.
Удаление дисков из пула не всегда будет доступно. В некоторых случаях потребуется прежде добавление нового устройства информации.
7. Переустановка Windows и подключение массива к другим компьютерам
Поддерживающие же технологию версии Windows при переустановке или подключении массива к другому компьютеру обнаружат его автоматически, без нашего вмешательства. Непосредственно во время переустановки ОС мы будем видеть массив как единое устройство информации. Кстати, если переустанавливается EFI -система Windows, необходима внимательность, чтобы по ошибке не удалить или не отформатировать MSR -раздел дискового пространства, а не ОС.
На дисковое пространство даже можно установить второю Windows. Вот только делать этого не стоит. Вторая ОС установится, но не сможет запускаться. Да и ещё и затрёт загрузчик первой ОС, и его придётся восстанавливать.
Пул компьютеров — это логическая группировка одной или нескольких тестовых систем. После установки Windows клиента HLK на каждой тестовой системе компьютеры автоматически добавляются в пул компьютеров по умолчанию. Прежде чем работать с тестовой системой, необходимо переместить ее в рабочий пул компьютеров.
Каждому проекту нужен пул компьютеров. Пул компьютеров можно использовать для нескольких проектов. Проект может ссылаться на несколько пулов компьютеров.
На следующем рисунке показана страница "Конфигурация Студии ".
3. Создание дискового пространства
В окно создания дискового пространства попадём автоматически сразу же после создания пула, а также при ручном запуске этой операции.
Здесь можем задать пространству любое имя и выбрать букву. Из обязательных настроек:
• Выбор типа устойчивости, по сути, конфигурации RAID ;
• Выбор файловой системы, если кроме NTFS предлагается ReFS ;
• Задание размера.
Размер, как упоминалось, можно установить любой, хоть и не обеспеченный носителями в пуле, на перспективу их добавления. Но если мы не собираемся больше ничего добавлять, тогда можем:
• Оставить значение по умолчанию для простого типа (RAID 0) , это будет суммарный объём всех носителей;
• Для отказоустойчивых массивов указать размер наименьшего по объёму диска.
Размер можем разделить на 2, 3, 4 и более частей. И создать несколько пространств по типу того, как мы на обычном диске формируем разные разделы для удобства каталогизации данных.
В итоге жмём кнопку создания.
Дисковое пространство в проводнике теперь станет доступно нам как обычный раздел. В управлении дисками носители пула больше не будут видны как отдельные устройства. И будут значиться по порядковому номеру последнего из них.
Архитектура пула потоков
Использование пула потоков может быть выгодным для следующих приложений:
- Приложение, которое имеет высокую степень параллельности и может асинхронно отправлять большое количество небольших рабочих элементов (например, Поиск распределенных индексов или сетевой ввод-вывод).
- Приложение, которое создает и уничтожает большое количество потоков, каждый из которых выполняется в течение короткого промежутка времени. Использование пула потоков может снизить сложность управления потоками и издержки, связанные с созданием и уничтожением потоков.
- Приложение, которое обрабатывает независимые рабочие элементы в фоновом режиме и параллельно (например, Загрузка нескольких вкладок).
- Приложение, которое должно выполнять эксклюзивное ожидание объектов ядра или блокировать входящие события объекта. Использование пула потоков может снизить сложность управления потоком и повысить производительность, уменьшая число переключений контекста.
- Приложение, которое создает пользовательские потоки ожидания для ожидания событий.
исходный пул потоков был полностью изменен в Windows Vista. Новый пул потоков улучшен, так как он предоставляет один тип рабочего потока (поддерживает операции ввода-вывода и без ввода-вывода), не использует поток таймера, предоставляет одну очередь таймера и предоставляет выделенный постоянный поток. Он также предоставляет группы очистки, более высокую производительность, несколько пулов для каждого процесса, которые планируются независимо, и новый API пула потоков.
Архитектура пула потоков состоит из следующих компонентов:
- Рабочие потоки, выполняющие функции обратного вызова
- Потоки ожидания, ожидающие нескольких дескрипторов ожидания
- Рабочая очередь
- Пул потоков по умолчанию для каждого процесса
- Рабочая фабрика, управляющая рабочими потоками
4. Тип устойчивости
Тип устойчивости – это функционал массива, аналог той или иной конфигурации RAID . Технология предлагает нам 4 таких типа.
Простой тип — это может как обычный раздел на базе одного или нескольких носителей, так и аналог RAID 0, массив как минимум из двух носителей без отказоустойчивости, но с удвоенной (как минимум) скоростью чтения и записи данных. При выходе из строя одного из дисков теряется вся информация. Файловая система – только NTFS .
Двухстороннее зеркало – это аналог RAID 1, отказоустойчивый массив из как минимум двух носителей. Данные одномоментно записываются на основной диск и зеркало, и так же одномоментно считываются. Имеем удвоенную скорость чтения данных и актуальные их копии на случай выхода из строя одного из носителей. Файловая система – и NTFS , и ReFS .
Трёхстороннее зеркало – это аналог RAID 1E, массив из как минимум пяти носителей, обеспечивающий быстродействие и высокую отказоустойчивость. Защищает данные в случае выхода из строя сразу двух дисков. Файловая система – и NTFS , и ReFS .
Чётность – это аналог RAID 5, массив из как минимум трёх носителей, обеспечивающий отказоустойчивость при выходе из строя одного из них. Увеличивается скорость чтения данных, но из-за специфики конфигурации несколько снижается скорость их записи. Файловая система – только NTFS .
Создание пула компьютеров
В Windows HLK Studio выберите "Конфигурация".
Чтобы создать первый новый пул, щелкните правой кнопкой мыши узел $(Root) и выберите команду "Создать пул компьютеров". При необходимости измените имя по умолчанию и нажмите клавишу ВВОД, чтобы завершить работу.
После создания пула можно также щелкнуть его правой кнопкой мыши и выбрать "Создать пул компьютеров". Пулы архива и по умолчанию имеют специальные роли, поэтому их нельзя использовать для создания нового пула.
Выберите пул по умолчанию и убедитесь, что каждая тестовая система отображается в главной области справа. Если вы установили клиент в нескольких тестовых системах, вы можете добавить в пул любой из них. Компьютер может находиться только в одном пуле одновременно.
Переместите тестовую систему в новый пул, сначала выбрав ее, а затем перетащив ее в только что созданный пул.
В области справа щелкните правой кнопкой мыши тестовую систему в столбце "Компьютеры" , выберите "Изменить состояние компьютера" и выберите пункт "Готово".
Столбец "Состояние " изменяется на "Готово".
- Вы не можете запланировать тест на компьютере со статусом NotReady.
- Компьютеру не удается установить значение Ready в пуле по умолчанию .
Повторите предыдущие два шага для каждой тестовой системы, которую вы хотите включить в пул.
После добавления всех тестовых систем в нужный пул компьютеров щелкните стрелку назад, чтобы вернуться в основную область Windows HLK Studio.
После размещения всех тестовых систем в пуле вы можете провести тестирование на этих компьютерах.
Дополнительные сведения о различных вариантах на этой странице, включая поддержку распределенных и нескольких устройств, см. на странице конфигурации HLK Studio.
5. Выход из строя одного из носителей
Дисковые пространства с отказоустойчивостью при выходе из строя одного или нескольких носителей продолжат своё функционирование. Но в окне технологии в панели управления увидим предупреждение о снижении отказоустойчивости. Конкретный носитель, с которым возникли проблемы, также будет отмечен предупреждением.
Рекомендации
Новый API пула потоков обеспечивает большую гибкость и управление, чем Исходный API пула потоков. Однако существует несколько незначительных, но важных отличий. В исходном API ожидание сброса было автоматическим; в новом API ожидание должно быть явным образом сброшено каждый раз. Исходный API, автоматически обрабатывающий олицетворение, передает контекст безопасности вызывающего процесса в поток. В новом API приложение должно явно задать контекст безопасности.
Ниже приведены рекомендации по использованию пула потоков.
Потоки процесса совместно используют пул потоков. Один рабочий поток может выполнять несколько функций обратного вызова по одной за раз. Эти рабочие потоки управляются пулом потоков. Поэтому не следует завершать поток из пула потоков путем вызова TerminateThread в потоке или путем вызова ExitThread из функции обратного вызова.
Запрос ввода-вывода может выполняться в любом потоке в пуле потоков. Для отмены ввода-вывода в потоке пула потоков требуется синхронизация, поскольку функция Cancel может выполняться в потоке, отличном от потока, обрабатывающего запрос ввода-вывода, что может привести к отмене неизвестной операции. Чтобы избежать этого, всегда выполняйте перекрывающиеся структуры, с помощью которых был инициирован запрос ввода-вывода при вызове канцелиоекс для асинхронного ввода-вывода, или используйте собственную синхронизацию, чтобы гарантировать, что никакие другие операции ввода-вывода не могут быть запущены в целевом потоке перед вызовом функции канцелсинчронаусио или канцелиоекс .
Очистите все ресурсы, созданные в функции обратного вызова перед возвратом из функции. К ним относятся TLS, контексты безопасности, приоритет потоков и регистрация COM. Функции обратного вызова также должны восстанавливать состояние потока перед возвратом.
Отслеживайте дескрипторы ожидания и связанные с ними объекты до тех пор, пока пул потоков не сообщит о завершении дескриптора.
Пометьте все потоки, ожидающие длительные операции (такие как очистка ввода-вывода или очистка ресурсов), чтобы пул потоков мог выделить новые потоки вместо ожидания этого.
Перед выгрузкой библиотеки DLL, использующей пул потоков, отмените все рабочие элементы, операции ввода-вывода, ожидания и таймеры и дождитесь завершения выполнения ответных вызовов.
Избегайте взаимоблокировок, удалив зависимости между рабочими элементами и обратными вызовами, убедившись, что обратный вызов не ждет завершения и, сохраняя приоритет потока.
Не ставить слишком много элементов слишком быстро в процесс с другими компонентами, использующими пул потоков по умолчанию. Существует один пул потоков по умолчанию для каждого процесса, включая Svchost.exe. По умолчанию каждый пул потоков имеет максимум 500 рабочих потоков. Пул потоков пытается создать больше рабочих потоков, когда число рабочих потоков в состоянии "Готово" или "выполняется" должно быть меньше числа процессоров.
Избегайте модели однопотокового апартамента COM, так как она несовместима с пулом потоков. STA создает состояние потока, которое может повлиять на следующий рабочий элемент для потока. Как правило, STA является длительным и имеет сходство потоков, что является противоположностью пула потоков.
Создание нового пула потоков для управления приоритетом и изоляцией потоков, создание пользовательских характеристик и, возможно, повышение скорости реагирования. Однако для дополнительных пулов потоков требуются дополнительные системные ресурсы (потоки, память ядра). Слишком большое количество пулов повышает вероятность состязаний за использование ЦП.
По возможности используйте ожидающий объект, а не механизм на основе APC для сигнализации потока пула потоков. APC не работают с потоками пула потоков в качестве других механизмов сигнализации, поскольку система управляет временем существования потоков пула потоков, поэтому поток может быть завершен до доставки уведомления.
Используйте расширение отладчика пула потоков,! TP. Эта команда имеет следующие сведения об использовании:
Для пула, ожидания и рабочей роли, если адрес равен нулю, команда создает дампы всех объектов. Для ожидающих и рабочих ролей пропуск адреса в дампе текущего потока. Определены следующие флаги: 0x1 (однострочный вывод), 0x2 (элементы дампа) и 0x4 (Рабочая очередь пула дампа).
Введение
- дорогие для создания и/или уничтожения объекты (примеры: сокеты, потоки, неуправляемые ресурсы);
- очистка объектов для переиспользования дешевле создания нового (или ничего не стоит);
- объекты очень большого размера.
- после выполнения работы с объектом может потребоваться его сброс в начальное состояние, чтобы предыдущее использование никак не влияло на последующие;
- пул должен обеспечивать потокобезопасность, ведь применяется он, как правило, в многопоточных системах;
- пул должен обрабатывать ситуацию, когда в нем не осталось доступных для выдачи объектов.
- Типобезопасность пула на этапе компиляции.
- Работа пула с любыми классами, в том числе сторонними.
- Простое использование в коде.
- Авто-выделение новых объектов при нехватке, их пользовательская инициализация.
- Ограничение общего количества выделенных объектов.
- Авто-очистка объекта при его возвращении в пул.
- Потокобезопасность (желательно, с минимальными расходами на синхронизацию).
- Поддержка множества экземпляров пула (отсюда вытекает хотя-бы простейший контроль того, чтобы объекты возвращались именно в свои пулы).
Решение проблем использования
В некоторых реализациях, для поддержки пулом объекта, объект должен реализовать интерфейс IPoolable или аналогичные, но моей задачей было обеспечение работы пула с любыми классами, даже если они закрыты для наследования. Для этого была создана generic-оболочка PoolSlot, которая внутри содержит сам объект и ссылку на пул. Сам же пул представляет собой абстрактный generic-класс для хранения этих слотов, с двумя нереализованными методами для создания нового объекта и очистки старого.
Использование на примере класса SocketAsyncEventArgs
Использование в коде:
Конечно, не каждый объект предоставляет пользователю такое свойство. И если ваш класс все-таки не закрыт от наследования, то предлагается специальный интерфейс IPoolSlotHolder с одним единственным свойством для хранения слота. И если я знаю, что мой объект гарантированно содержит слот, то было бы логичным дописать методы TakeObject/Release, возвращающие/принимающие сами объекты (и получать их слот внутри), что и было сделано в потомке пула.
Далее я предлагаю ознакомиться с разработкой внутренней «кухни».
Хранилище
Для хранения объектов «в пуле» используется коллекция ConcurrentStack. Возможное использование нескольких экземпляров пула потребовало ведение учета, какой из объектов был создан именно этим пулом.
Так был введен «реестр» на основе ConcurrentDictionary, который содержит ID слотов, когда-либо созданных пулом и флаг доступности объекта (true — «в пуле», false — «не в пуле»).
Это позволило убить сразу 2х зайцев: предотвратить ошибочное многократное возвращение одного и того же объекта (ведь стек не обеспечивает уникальности хранимых в нем объектов) и предотвратить возвращение объектов, созданных в другом пуле. Данный подход был временным решением, и далее я от него избавился.
Многопоточность
- Пытаемся взять объект из хранилища, если там нету — пункт 2.
- Пытаемся создать новый объект, если семафор равен нулю (достигнут верхний лимит) — пункт 3.
- Самый плохой сценарий — ожидаем возвращение объекта до победного конца.
Первые результаты, оптимизация и рефакторинг
Так ли нужен пул объектов? Зависит от ситуации. Вот результаты небольшого тестирования с использованием «типичного серверного объекта», SocketAsyncEventArgs с буфером на 1024 байта (время в секундах, создание пула включено):
Запросов нового объекта | Один поток, без пула | Один поток, с пулом | 25 задач*, без пула | 25 задач*, с пулом |
1 000 | 0.002 | 0.003 | 0.027 | 0.009 |
10 000 | 0.010 | 0.001 | 0.272 | 0.039 |
25 000 | 0.030 | 0.003 | 0.609 | 0.189 |
50 000 | 0.048 | 0.006 | 1.285 | 0.287 |
1 000 000 | 0.959 | 0.125 | 27.965 | 8.345 |
* задача — класс System.Threading.Tasks.Task из библиотеки TPL, начиная с .NET 4.0
Результаты прохода профилировщика VS2012 по многопоточному тесту с пулом:
Как видим, все упирается в метод ConcurrentStack.TryPop, который (будем считать) ускорять некуда. На втором месте обращение к «реестру», который отбирает примерно по 14% в обеих операциях.
В принципе, поддержка второй коллекции внутри пула и так казалась мне костыльной, поэтому признак «в пуле/не в пуле» был перенесен в сам слот, а реестр благополучно удален. Результаты тестов после рефакторинга (прирост, как и ожидалось, 30-40%):
Запросов нового объекта | 25 задач, с пулом |
25 000 | 0.098 |
1 000 000 | 5.751 |
Думаю, на этом можно остановиться.
Заключение
- Типобезопасность на этапе компиляции — использование generic-классов.
- Работа пула с любыми классами — использование generic-оболочки без наследований.
- Облегчение использования — конструкция using (реализация оболочкой интерфейса IDisposable).
- Авто-выделение новых объектов — абстрактный метод Pool.ObjectConstructor, в котором инициализируется объект как душе угодно.
- Ограничение количества объектов — облегченный вариант семафора.
- Авто-очистка объекта при его возвращении — виртуальный метод Pool.CleanUp, который автоматически вызывается пулом при возвращении.
- Потокобезопасность — использование коллекции ConcurrentStack и CAS-операций (методов класса Interlocked).
- Поддержка множества экземпляров пула — класс Pool не статический, не синглтон и обеспечивает проверки на допустимость операций.
Исходный код с unit-тестами и тестовым приложением: Github
Если интересно, могу продолжить статью реализацией асинхронных TCP и UDP сокет-серверов, для которых данный пул как раз и писался.
Пул памяти – это блок памяти, назначенный конкретной программе или приложению на компьютере. Информация для запущенной программы, такой как операционная система или любое открытое приложение на компьютере, хранится в памяти произвольного доступа (ОЗУ) на компьютере. Присвоение каждой программе определённого блока памяти с использованием технологии пула памяти позволяет избежать проблемы перекрытия памяти. Перекрытие происходит, когда две программы пытаются использовать одни и те же разделы памяти; например, пытаясь разделить кусочек пирога, программы могут «сражаться» за разделяемую память, что приводит к ошибкам в системе.
C пулом памяти каждая программа получает свой собственный «срез», что приводит к гармоничной работе компьютера. Пользователь может думать о ОЗУ на компьютере, как о простой многоэтажной книжной полке. Без использования пула памяти, когда информация поступает, компьютер только начинает заполнять полки сверху донизу без разбора, сплайсируя информацию, чтобы в памяти не существовало линейной логической структуры. Хотя это полностью действительный подход к обработке памяти, для организации скорости работы, но недостатком является то, что программы удаляются из памяти, а новые программы занимают их место. Скорее всего, информация, необходимая новой программе, не будет плотно вписываться в освобожденные пробелы, поскольку старая программа была удалена. Без объединения памяти это несоответствие заставляет компьютер ещё больше нарушать организацию в ОЗУ – это называется фрагментацией.
Наличие фрагментированной информации в памяти означает, что компьютеру придётся выполнить действие жонглирования для извлечения информации для какой-либо конкретной программы. С пулом памяти фрагментация минимизируется, поскольку компьютер назначает каждой программе определенную область в «книжной полке» памяти, сводя к минимуму риск дезорганизации. Это приводит к небольшому количеству дополнительных расходов на компьютере с самого начала, так как он должен выполнять своё «жонглирование» памяти при первой загрузке программы, но существенно повышает эффективность программы во время её работы, поскольку компьютер уже знает на какой «полке» посмотреть для поиска информации о программе.
Операционная система обычно контролирует работу пула памяти. Она имеет возможность распределять и переупорядочивать различные «пулы» в ОЗУ компьютера, при необходимости настраивая требования отдельных приложений. Например, если приложение запрашивает больший блок памяти, чем ему был назначен, операционная система должна действовать, чтобы увеличить конкретный пул, назначенный этой программе, без вмешательства в пулы памяти других активных программ в системе. Оптимизация требует, чтобы конкретное приложение настраивалось для конкретной операционной системы и наоборот, гарантируя, что обе вместе работают, чтобы максимально распределить и зарезервировать память для приложения.
Windows в числе своего арсенала предусматривает несколько возможностей по созданию программного RAID . Это в первую очередь старая системная функция по работе с динамическими дисками, в рамках которой можно, в частности, создавать специальные разделы из нескольких устройств информации с реализацией конфигураций RAID 0, 1 и 5. А Win8.1 и Win10 на своём борту содержат более современную технологию – дисковые пространства.
Что это за технология и как её использовать?
1. О технологии
Итак, в версиях Windows 8.1 и 10 реализована технология по типу программного RAID , называется «Дисковые пространства». Реализована в панели управления.
Предназначается для создания производительных и отказоустойчивых дисковых массивов. С помощью этой технологии можем два и более жёстких диска объединить в одно дисковое пространство, по сути, в единый пользовательский (несистемный) раздел. И хранить на этом разделе что-то не особо важное в случае конфигурации без отказоустойчивости или, наоборот, что-то важное, обеспечив этим данным двух- или трёхсторонние зеркала. Дисковые пространства могут быть сформированы из разного типа устройств информации – внутренних SATA , SAS и внешних USB-HDD .
Чем эта технология отличается от динамических дисков? Дисковые пространства:
• В большей степени эмулируют аппаратный RAID ;
• Лишены многих недостатков динамических дисков;
• При зеркалировании позволяют задействовать относительно современную наработку Microsoft - отказоустойчивую файловую систему ReFS ;
• Не предусматривают, как динамические диски, возможность зеркалирования самой Windows (очевидно, как лишней функции в свете иных возможностей восстановления работоспособности ОС) .
Дисковое пространство – это территория с нуля, при её создании жёсткие диски форматируются, их структура и содержимое теряются. Тогда как при работе с динамическими дисками мы к любому существующему разделу без потери данных можем добавить его раздел-зеркало.
Как и динамические диски, современная технология программного RAID позволяет создавать массивы из разных жёстких дисков, в том числе и по объёму. Но последняя, в отличие от первой, не оставляет незанятое массивом место на одном из носителей меньшего объёма. Чтобы это незанятое место можно было присоединить к другим разделам или создать отдельный раздел. Наоборот, при создании дисковых пространств мы не ограничены объёмом одного из жёстких. Мы можем изначально указать любой виртуальный размер, а впоследствии обеспечить его реальными ресурсами устройств информации, добавив их к массиву - так называемому пулу носителей. Реализация последнего позволяет нам действовать несколько гибче, чем при оперировании динамическими дисками.
Читайте также: