Ограничиваем потоки шаблона

ebrwebrw

Client
Регистрация
20.08.2018
Сообщения
221
Благодарностей
163
Баллы
43
Добавлю сюда что бы не потерялось на форуме

Вариант #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("Привышен лимит по потокам");
}

}
PS лок замените только на свой, по этому гайду допустим
PPS для обновления времени активности потока нужно вызывать этот код в процессе работы в разных местах шаблона, по этому лучше перенести в общий код или dll

PPPS
Нужно задать идентификатор потока который на протяжении выполнения потока не будет изменяться, можно создать переменную допустим thread_id и генерировать её в самом начале шаблона, далее добавить её в тот код выше
C#:
string thread_identifier = project.Variables["thread_id"].Value;
PPPPS тестировал мало, т.к делал из за интереса, если будут баги пишите, постараюсь пофиксить
 
Последнее редактирование:

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)