- Регистрация
- 20.08.2018
- Сообщения
- 221
- Благодарностей
- 164
- Баллы
- 43
Добавлю сюда что бы не потерялось на форуме
Вариант #1 через TasksList и LimitOfThreads
Вариант #2 через глобальную переменную
По сути сюда можно прикрутить проверку на своём сервере за место глобальной переменной и так решим проблему с виртуалками
Логика кода ниже такая:
Код читает глобалку, проверяет наличие в ней идентификатора потока,
если поток найден то обновляет время активности и перезаписывает глобальную переменную с новой информации о потоке
если идентификатор потока не найден в глобальной переменной, код проверяет время активности всех потоков, если какой либо поток более заданного времени не обновлял информацию о активности - удаляет его из активных потоков, освобождая место другим
Далее идёт проверка лимита на количество активных потоков
если колво активных потоков меньше заданного лимита - записывает информацию о новом потоке
если колво активных потоков равно заданному лимиту - запрещает запуск
PS лок замените только на свой, по этому гайду допустим
PPS для обновления времени активности потока нужно вызывать этот код в процессе работы в разных местах шаблона, по этому лучше перенести в общий код или dll
PPPS
Нужно задать идентификатор потока который на протяжении выполнения потока не будет изменяться, можно создать переменную допустим thread_id и генерировать её в самом начале шаблона, далее добавить её в тот код выше
PPPPS тестировал мало, т.к делал из за интереса, если будут баги пишите, постараюсь пофиксить
Вариант #1 через TasksList и LimitOfThreads
C#:
//название шаблона который будем выдавать
string template_name = "test_limit".Replace(".xmlz","").ToLower();
//Максимальное колво потоков
int threads_limit = 3;
string project_name = project.Name.Replace(".xmlz","").ToLower();
if (template_name != project_name) throw new Exception("Нельзя переименовывать шаблон");
lock(SyncObject){
var tasksList = ZennoPoster.TasksList;
//Обнуляем счетчик потоков
int all_threads = 0;
int template_count = 0;
foreach (var task in tasksList){
string tname = Regex.Match(task,@"(?<=<Name>).*?(?=</Name>)").Value.ToLower();
if(tname == template_name)
{
template_count=template_count+1;
//получаем колво потоков
int threads = Convert.ToInt32(Regex.Match(task.ToString(),@"(?<=<LimitOfThreads>).*?(?=</LimitOfThreads>)").Value);
//return task;
project.SendInfoToLog(Convert.ToString(threads));
//return threads;
//суммируем потоки для шаблонов с одинаковым названием
all_threads=all_threads+threads;
}
//project.SendInfoToLog(Convert.ToString(all_threads));
// project.SendInfoToLog(tname);
}
//project.SendInfoToLog(Convert.ToString(template_amount));
if(template_count >1)throw new Exception("Разрешенно использование только 1 шаблона одновременно");
if(all_threads>threads_limit) throw new Exception("Привышенно максимальное количество потоков, лимит: "+Convert.ToString(threads_limit));
}
Вариант #2 через глобальную переменную
По сути сюда можно прикрутить проверку на своём сервере за место глобальной переменной и так решим проблему с виртуалками
Логика кода ниже такая:
Код читает глобалку, проверяет наличие в ней идентификатора потока,
если поток найден то обновляет время активности и перезаписывает глобальную переменную с новой информации о потоке
если идентификатор потока не найден в глобальной переменной, код проверяет время активности всех потоков, если какой либо поток более заданного времени не обновлял информацию о активности - удаляет его из активных потоков, освобождая место другим
Далее идёт проверка лимита на количество активных потоков
если колво активных потоков меньше заданного лимита - записывает информацию о новом потоке
если колво активных потоков равно заданному лимиту - запрещает запуск
C#:
string NameSpace = "1234567890";
string VariableName = "template_name";
string [] threads = {"thread_1","thread_2","thread_3","thread_4","thread_5","thread_6"};
string thread_identifier = threads[Global.Classes.rnd.Next(0,threads.Count())];
//thread_identifier = project.Variables["thread_id"].Value;
int limit_thread = 5;
int free_after_sec = 30;//если поток не используется заданное время - освобождаем
bool isUpdate = false;
string thread_info = string.Empty;
List<string> List_threads_info = new List<string>();
lock(SyncObject){
project.SendInfoToLog("Запуск потока: "+thread_identifier);
int UnixTime = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
//чтения информации о потоках из глобальной переменной
try
{
thread_info = Convert.ToString(project.GlobalVariables[NameSpace,VariableName]);
}
//Если переменной нет - создаем
catch
{
project.SendInfoToLog("Переменной нет, создаем",true);
project.GlobalVariables.SetVariable(NameSpace, VariableName, "["+thread_identifier+","+Convert.ToString(UnixTime)+"];");
thread_info = Convert.ToString(project.GlobalVariables[NameSpace,VariableName]);
}
//project.SendInfoToLog("Информация в глобальной переменной: "+thread_info);
//парсим все данные из глобальной переменой в лист
List_threads_info=thread_info.Split(new char[] {';'},StringSplitOptions.RemoveEmptyEntries).ToList();
project.SendInfoToLog("Количество потоков: "+Convert.ToString(List_threads_info.Count),true);
//перебор списка с данными о потоках
for(int i=0;i<List_threads_info.Count;i++){
string info = List_threads_info[i];
project.SendInfoToLog(info);
//получаем время ласт использования потока
int last_update_time = Convert.ToInt32(Regex.Match(info,"(?<=,).*(?=])").Value);
string thread_name = Regex.Match(info,@"(?<=\[).*(?=,)").Value;
if(thread_identifier==thread_name)
{
project.SendInfoToLog("Обновляем время активности потока",true);
List_threads_info[i]="["+thread_identifier+","+Convert.ToString(UnixTime)+"]";
isUpdate = true;
break;
}
//если поток не активен заданное время то удаляем его из списка
if((last_update_time+free_after_sec)<UnixTime){
project.SendInfoToLog("Удаляем поток из списка занятых из за неактивности",true);
List_threads_info.Remove(List_threads_info[i]);
i--;
}
}
//если строк в списке меньше чем int limit_thread или происходит обновление времени активности потока
if(List_threads_info.Count <limit_thread | isUpdate) {
//project.SendInfoToLog("Разрешаем запуск потока",true);
//добавляем инфу о новом потоке
if(!isUpdate){
project.SendInfoToLog("Разрешаем запуск потока",true);
List_threads_info.Add("["+thread_identifier+","+Convert.ToString(UnixTime)+"]");
}
//переводим список в строку
string threads_info_to_gloval = string.Join(";", List_threads_info);
//перезаписываем глобалку
project.SendInfoToLog("Перезаписываем инфу о потоках: "+threads_info_to_gloval,true);
project.GlobalVariables.SetVariable(NameSpace, VariableName, threads_info_to_gloval);
}
else //если лимит
{
project.SendInfoToLog("Запрещаем запуск потока",true);
throw new Exception("Привышен лимит по потокам");
}
}
PPS для обновления времени активности потока нужно вызывать этот код в процессе работы в разных местах шаблона, по этому лучше перенести в общий код или dll
PPPS
Нужно задать идентификатор потока который на протяжении выполнения потока не будет изменяться, можно создать переменную допустим thread_id и генерировать её в самом начале шаблона, далее добавить её в тот код выше
C#:
string thread_identifier = project.Variables["thread_id"].Value;
Последнее редактирование: