Usuário com melhor resposta
Разработка службы в Visual Studio

Pergunta
-
Написал службу, которая опрашивает БД и в зависимости от значения столбца Enabled добавляет или удаляет пользователя из группы AD. Служба работает, однако грузит процессор на 20%. Ниже привожу класс в котором выполняются все действия службы
class AccessControl { public void AddUserToGroup(string username, string groupname) // Добавляет юзера в группу { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "MARINA")) { GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupname); group.Members.Add(pc, IdentityType.SamAccountName, username); group.Save(); } } public void RemoveUserFromGroup(string username, string groupname) // Удаляет юзера из группы { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "MARINA")) { GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupname); group.Members.Remove(pc, IdentityType.SamAccountName, username); group.Save(); } } public bool IsUserFromGroup(string username, string groupname) // Проверяет членство юзера в группе { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "MARINA")) { GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupname); bool res = group.Members.Contains(pc, IdentityType.SamAccountName, username); return res; } } public void Start() { AccessControls(true); // Запускает цикл } public void Stop() { AccessControls(false); // Останавливает цикл } public void AccessControls(bool stat) // Основная функция службы { while (stat == true) { string connectionString = @"Data Source=MBS1\MARINA_SQL;Initial Catalog=INTERNET_SQL;Integrated Security=True"; // Строка подключения к БД string queryString = "SELECT UserName FROM dbo.UsersWithAccess WHERE Enabled = 1"; // Запрос списка пользователей, которым разрешен доступ в инет List<String> usernames = new List<String>(); using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(queryString, connection); connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { usernames.Add(reader.GetString(0)); // Сохранение списка в массив } } foreach (String username in usernames) // Перебор элементов массива { bool result = IsUserFromGroup(username, "internet_full_permit"); // Проверка членства пользователя в группе if (result == false) { AddUserToGroup(username, "internet_full_permit"); // Добавление юзера в группу } } queryString = "SELECT UserName FROM dbo.UsersWithAccess WHERE Enabled = 0"; // Запрос списка пользователей которым запрещен доступ в инет List<String> usernames2 = new List<String>(); using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(queryString, connection); connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { usernames2.Add(reader.GetString(0)); // Сохранение списка в массив } } foreach (String username in usernames2) // Перебор элементов массива { bool result = IsUserFromGroup(username, "internet_full_permit"); // Проверка членства пользователя в группе if (result == true) { RemoveUserFromGroup(username, "internet_full_permit"); // Удаление пользователя из группы } } } } }
Помимо этого при работе службы процесс lsass.exe начинает также грузить процессор примерно на 10%.
Пробовал запускать службу как на DC с Win Server 2008 R2, так и на своем компе с Win7 Pro - на компе служба не создает такой нагрузки на процессор, как на DC или рядовом сервере.
На компе - служба - 3...5%, lsass.exe - 0%
На DC - служба 16...20%, lsass.exe - 10...12%Подскажите пожалуйста, как можно уменьшить нагрузку на процессор создаваемую этой службой?
- Editado R2DDD sábado, 5 de dezembro de 2020 19:46
Respostas
-
Следует перестать крутить бесконечный цикл без перерывов. Такой цикл по определению будет на 100% загружать одно ядро. Возможно больше если где то используется многопоточность.
В простейшем случае это можно сделать добавив период ожидания после каждого опроса. Я так думаю вполне допустимо чтоб опрос происходил раз в несколько секунд, например 10. Для реализации достаточно вставить данный код в любое место цикла, обычно в конец:
Thread.Sleep(10000); // Подождем 10 секунд чтоб не грузить процессор.
Так же у вас неправильно реализована остановка цикла.
This posting is provided "AS IS" with no warranties, and confers no rights.
- Marcado como Resposta R2DDD sábado, 5 de dezembro de 2020 23:41
Todas as Respostas
-
Следует перестать крутить бесконечный цикл без перерывов. Такой цикл по определению будет на 100% загружать одно ядро. Возможно больше если где то используется многопоточность.
В простейшем случае это можно сделать добавив период ожидания после каждого опроса. Я так думаю вполне допустимо чтоб опрос происходил раз в несколько секунд, например 10. Для реализации достаточно вставить данный код в любое место цикла, обычно в конец:
Thread.Sleep(10000); // Подождем 10 секунд чтоб не грузить процессор.
Так же у вас неправильно реализована остановка цикла.
This posting is provided "AS IS" with no warranties, and confers no rights.
- Marcado como Resposta R2DDD sábado, 5 de dezembro de 2020 23:41
-
-
Спасибо за совет, помогло. Да, 10 секунд вполне допустимо.
Скажите пожалуйста, а каким образом тогда правильнее выходить из цикла?
Вы вообще не выходите из цикла, просто вызывайте метод второй раз и он возвращает управление ничего не сделав.
Чтоб остановить цикл нужно использовать переменную в классе которая будет проверяться в потоке где крутится цикл, а изменятся в потоке который будет останавливать цикл:
private bool keepRunning = true;
void Stop()
{
keepRunning = false;
// Тут можно подождать семафор который подтвердит выход из цикла.
}
void Runner()
{
while (keepRunning)
{
// Тут надо делать что надо, но не очень долго за раз.
}
// Тут можно установить семафор чтоб подтвердить выход из цикла.
}
This posting is provided "AS IS" with no warranties, and confers no rights.
- Sugerido como Resposta Alexander RusinovModerator domingo, 6 de dezembro de 2020 10:32
-
А возможно ли свести все к одному запросу к БД?
Попробовал сделать путем добавления результата запроса в коллекцию, однако получил ошибку: "Индекс за пределами диапазона. Индекс должен быть положительным числом, а его размер не должен превышать размер коллекции. Имя параметра: index". Ошибка возникает на строке
usernames[usernames.Count - 0][0] = reader[0].ToString();
Вот фрагмент кодаList < String[]> usernames = new List<String[]>(); using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(queryString, connection); connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { usernames.Add(new string[2]); // Сохранение списка в массив usernames[usernames.Count - 0][0] = reader[0].ToString(); usernames[usernames.Count - 1][1] = reader[1].ToString(); } }
-
В общем случае это это зависит от схемы базы и запроса. Смотрите сами что возвращает запрос.
Что до исключения, то проблема может быть тут:
usernames[usernames.Count - 0]
В списке для начала находится один элемент с индексом 0, при этом Count = 1.
1 - 0 = 1
Это обращение к элементу с индексом 1, а у вас его нет. Получается выход за пределы списка.
This posting is provided "AS IS" with no warranties, and confers no rights.
-
В базе 2 таблицы, никак между собой не связанные. Первая - та, которая опрашивается службой. Вторая - лог.
Пробовал изменить usernames[usernames.Count - 0] на usernames[usernames.Count - 1] и т.д. остальные подобные строки - безрезультатно. Исключение стало возникать на 2 строке.
Запрос простейший SELECT UserName, Enabled FROM dbo.UsersWithAccess
У UserName тип данных nvarchar(50) а у Enabled - int
-
-