Управление шаблоном c#

Porosenok

Client
Регистрация
26.09.2010
Сообщения
1 208
Благодарностей
77
Баллы
48
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
Как вариант я могу добавить несколько версий одного шаблона, но с разными шаблонами, получится в таком случае получить имя шаблона в ЗП (я могу например добавить template.xlmz, но назвать template1, template2)?
 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
865
Благодарностей
807
Баллы
93
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
Делать копии проекта (и копировать файл проекта) и настраивать им нужные входящие.
 
  • Спасибо
Реакции: Porosenok

Porosenok

Client
Регистрация
26.09.2010
Сообщения
1 208
Благодарностей
77
Баллы
48
Тогда нужно для автоматизации батник писать, чтобы раскопировать родной шаблон после каждой правки
 

Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
5 883
Благодарностей
3 041
Баллы
113
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
ZennoPoster.AddTask может создать несколько задач на один шаб.
Обязательные параметры:
Id, Name, IsNewbie, IsEnable, CreateTime, SettingsType
в ExecutionSettings: LimitOfThreads, MaxAllowOfThreads
в Project: ProjectFileLocation, ProjectType

CreateTime обязательно должен отличаться, иначе входные у задач будут одинаковые.
ProjectFileLocation - должен указывать на целевой шаб.

Либо, после запуска потока, загружать другие входные настройки.
 
  • Спасибо
Реакции: Porosenok

ZSharp

Client
Регистрация
29.09.2013
Сообщения
343
Благодарностей
83
Баллы
28
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
Как вариант я могу добавить несколько версий одного шаблона, но с разными шаблонами, получится в таком случае получить имя шаблона в ЗП (я могу например добавить template.xlmz, но назвать template1, template2)?
Добавить в ZP шаблон (template.xmlz) и переименовать его в самом ZP (template1) (не файл), задать входные настройки.
Затем добавить ТОТ ЖЕ шаблон (template.xmlz) в ZP и опять его переименовать в ZP (template2) (не сам файл) и задать другие входные настройки и т.д.

Единственное что после изменения шаблона чаще всего слетают входные настройки, но их можно сохранить в файл и восстановить потом из файла, зато не нужно будет открывать шаблон заново после обновы, и все настройки от ZP прокси, расписание и т.д. останутся.

Входные настройки сохраняю как имя переименованного шаблона в ZP (template1.xml) рядом с файлом (template.xmlz).
 

Porosenok

Client
Регистрация
26.09.2010
Сообщения
1 208
Благодарностей
77
Баллы
48
Да, оказалось что один шаблон, добавленный несколько раз имеет разные айдишки.
Теперь пару вопросов:
1) А как стартовать шаблон? Допустим он на паузе, я добавил попыток, но как его запустить? StartTask метод?
2) Почему данный код не срабатывает, попытки не добавляются
C#:
string tempname = "Template";
if (OwnCode.CommonCode.TaskHelper.GetTaskId(tempname)==""){
  project.SendErrorToLog("Не смогли найти проект "+tempname, true);
  throw new Exception("Не найден проект");
} else {

    project.SendInfoToLog(OwnCode.CommonCode.TaskHelper.GetTaskId(tempname));
    ZennoPoster.AddTries(OwnCode.CommonCode.TaskHelper.GetTaskId(tempname), 50);
}
Хотя айдишка отлично парсится. В чем дело? Пробовал SetTries вместо AddTries, так же не работает.
3)Как-то можно количество успехов редактировать? - нашел, через SetExecutionSettings
А как можно получить изначальные настройки выполнения? - нашел, через GetTaskInfo
 
Последнее редактирование:
Регистрация
05.06.2019
Сообщения
570
Благодарностей
446
Баллы
63
up

Очень интересна данная тема, хочу реализовать стек задач, то есть:
1-ый шаблон выполняет роль "диспетчера задач", который в свою очередь:
а) загружает таски из бд,
б) включает 2-ой шаблон, выставляет нужное кол-во потоков/выполненний.

Во 2-ом шаблоне главный процесс, запускает параллельные потоки, которые ждут сигнала от главного процесса (2-ого шаблона, своего рода менеджер аккаунтов/заданий). После чего распределяет таски (из 1-ого шаблона) по параллельным потокам (возможно через папки/файлы, пример: уникальное название папки token_session_task (генерирует уникальный номер сессии: ada123987AWDwd7, на время жизни 1 потока). Но по сути, жизнь 1 потока, не заканчивается по окончанию задачи, а ожидает от главного процесса новой инструкции. То есть, главный процесс контролирует статистику выполнения, по окончанию списка заданий, отправляет запрос на новую пачку заданий из 1-ого шаблона (диспетчер задач). Если заданий нет, то 1-ый шаблон глушит 2-ой (до поступления новых задач из центральной бд) или скидывает к минимальному кол-во потоков, к примеру 5 на 15 мин, если в течение этого времени из центральной бд не поступило заданий (их нет в бд), то глушится 2-ой шаблон, а первый шаблон продолжает чекать бд.

Вывод: По сути это стол заказов online, поступила задача, сразу выполняется, если нет, то работает на холостых.

П.С. Я новичок, еще многие алгоритмы и реализацию не познал, но заметил, что Lord_Alfred строил похожую логику.
Вопрос: На практике данный алгоритм актуальный для реализации или это костыль костыльный?

Не в замудренности дело :-) Кому надо - тот разберется, а вот кому интересно, но не хватает знаний - не хватит желания дойти до конца и понять какой метод для чего использовать.
Именно поэтому в опен сорс проектах и делают документацию, чтоб повысить количество тех, кто будет использовать проект, ведь без пользователей - и смысла в опенсорсе нету)
Поддерживаю!
 
Последнее редактирование:

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 919
Благодарностей
3 809
Баллы
113
П.С. Я новичок, еще многие алгоритмы и реализацию не познал, но заметил, что Lord_Alfred строил похожую логику, вопрос, на практике данных алгоритм актуальный или это костыл костыльный?
Я нахватал шишек с похожей логикой :-)
Сейчас все шаблоны с похожими задачами делаю следующим образом: в MySQL храню в столбце "состояние" текущей строки и просто запускаю шаблон каждую минуту (через стандартные средства расписания в ZP), где внутри проверяю есть ли доступные задания. Иногда запускаю в работу не 1, а сразу 5-10 потоков.
Да, бывают ситуации, когда в базе накапливается больше строк для работы, чем добавляется потоков каждую минуту, но тут ничего не сделаешь. Ибо всё равно есть предел ресурсам, лучше их ограничивать по максимальному количеству потоков, а не запускать новый поток с каждым появившимся заданием.
Ну и такую логику гораздо проще дебажить + в случае ошибки внутри шаблона - менять статус в базе обратно.
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
10 749
Благодарностей
5 128
Баллы
113
Я нахватал шишек с похожей логикой :-)
Сейчас все шаблоны с похожими задачами делаю следующим образом: в MySQL храню в столбце "состояние" текущей строки и просто запускаю шаблон каждую минуту (через стандартные средства расписания в ZP), где внутри проверяю есть ли доступные задания. Иногда запускаю в работу не 1, а сразу 5-10 потоков.
Да, бывают ситуации, когда в базе накапливается больше строк для работы, чем добавляется потоков каждую минуту, но тут ничего не сделаешь. Ибо всё равно есть предел ресурсам, лучше их ограничивать по максимальному количеству потоков, а не запускать новый поток с каждым появившимся заданием.
Ну и такую логику гораздо проще дебажить + в случае ошибки внутри шаблона - менять статус в базе обратно.
а еще так проще наращивать базу заданий, не останавливая на время разработки новой задачи, всю систему. :bf:
 

Mazamaka

Client
Регистрация
12.12.2018
Сообщения
8
Благодарностей
3
Баллы
3
как добавить количество потоков?
 
  • Спасибо
Реакции: Swanskey
Регистрация
12.07.2014
Сообщения
916
Благодарностей
370
Баллы
63
  • Спасибо
Реакции: Mazamaka

elakeri

Client
Регистрация
23.07.2018
Сообщения
169
Благодарностей
10
Баллы
18
Часто задают вопросы, как запустить шаба из шаба, как управлять, добавить потоки итд.
Люди начинают создавать некошерные батники и прочими образами извращаться, хотя зенка предоставляет не очень приличный, но достаточный api для решения этих вопросов более адекватным путем.
Выкладываю небольшой статический класс упрощающий работу с запуском вторичных шабов.

Класс вставляем в общий код после
Код:
namespace ZennoLab.OwnCode
{

Код:
public static class TaskHelper
   {
    
       public static string GetTaskId(string TaskName)
     {
       var tasksList = ZennoPoster.TasksList;
       foreach (var task in tasksList){        
        string tname = Regex.Match(task,@"(?<=<Name>).*?(?=</Name>)").Value;
          string tid  = Regex.Match(task,@"(?<=<Id>).*?(?=</Id><Name>)").Value;
        
          if (tname == TaskName){
           return tid;
          }
       }  
       return "";
     }
    
     public static int GetNumberOfTries(string TaskName)
     {
         string sid = TaskHelper.GetTaskId(TaskName);
       var id = Guid.Parse(sid);
       var taskInfo = ZennoPoster.GetTaskInfo(id);
       string execsettings = Regex.Match(taskInfo,@"(?<=<ExecutionSettings>).*?(?=</ExecutionSettings>)").Value;
       string ntries =  Regex.Match(execsettings,@"(?<=<NumberOfTries>).*?(?=</NumberOfTries>)").Value;
       int res=0;
       Int32.TryParse(ntries,out res);
       return res;      
     }
    
     public static string GetStatus(string TaskName)
     {
       string sid = TaskHelper.GetTaskId(TaskName);
       var id = Guid.Parse(sid);
       var taskInfo = ZennoPoster.GetTaskInfo(id);
       string status = Regex.Match(taskInfo,@"(?<=<Status>).*?(?=</Status>)").Value;
       return status;
      
       //Perform - работает
       //Complite - завершен
       //Stop - остановлен
       //Schedule - запланирован
       //WaitPerform - компилится
     }
    
     public static void WaitRun(IZennoPosterProjectModel project,string TaskName)
     {
         int nt = GetNumberOfTries(TaskName);
       string status = GetStatus(TaskName);
       while( nt >0 )
       {   
         if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return; // Прерывание в ZP
         if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return; // Прерывание в PM
        
           Thread.Sleep(3000);
        
           nt = TaskHelper.GetNumberOfTries(TaskName);
         status = GetStatus(TaskName);
        
         switch (status)
         {
           case "Perform":
             break;
           case "Complite": nt = 0;
             break;
           case "Stop": nt = 0;
             break;
           case "Schedule":
             break;
           case "WaitPerform":
             break;
         }
        
           project.SendInfoToLog("Ожидаем завершения "+TaskName,true);  
       }
     }
   }
Примеры использования

Поиск айди шаблона по имени:
Код:
string tempname = "имя шаба";
if (TaskHelper.GetTaskId(tempname)==""){
  project.SendErrorToLog("Не смогли найти проект "+tempname, true);
  throw new Exception("Не найден проект");
}
Добавление нужного числа исполнений и ожидание завершения:
Код:
string tempname = "имя шаба";
int tries = 50; // будет добавлено 50 исполнений
if (tries>0){
   ZennoPoster.AddTries(tempname , tries);
   TaskHelper.WaitRun(project,tempname );  //ожидаем завершения всех исполнений
}
GetStatus - получить статус шаблона
Код:
//Perform - работает
//Complite - завершен
//Stop - остановлен
//Schedule - запланирован
//WaitPerform - компилится
GetNumberOfTries - получить кол-во заданых исполнений
почему то в постере не ждет завершение всех исполнений шаблона..., сразу идет дальше.., в пр мэйкере ждет.., с чем может быть связано, не подскажете?
 
Регистрация
12.07.2014
Сообщения
916
Благодарностей
370
Баллы
63
почему то в постере не ждет завершение всех исполнений шаблона..., сразу идет дальше.., в пр мэйкере ждет.., с чем может быть связано, не подскажете?
Да бывает такое.
Я из шаблона запускал парсер Орка на Гетах. В парсере еще делаю постинг в БД unixtime.
И в основном шабе брал этот unixtime и проверял сколько времени прошло с последнего обновления времени.
 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
865
Благодарностей
807
Баллы
93
Вкратце результат исследования, но пока не подтверждено тестами: AddTries у нас оказалось асинхронкой и в результате, если идет схема
Код:
ZennoPoster.AddTries(tempname , tries);
TaskHelper.WaitRun(project,tempname );
То WaitRun может получить неверное кол-во запущеных потоков, тк. AddTries их еще не запустило. Поэтому достаточно добавить паузу перед ожиданием и должно работать стабильно.
Код:
string tempname = "имя шаба";
int tries = 50; // будет добавлено 50 исполнений
if (tries>0){
   ZennoPoster.AddTries(tempname , tries);
   System.Threading.Thread.Sleep(1000);
   TaskHelper.WaitRun(project,tempname );  //ожидаем завершения всех исполнений
}
 

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
13 492
Благодарностей
5 082
Баллы
113
GetStatus - получить статус шаблона
Код:
//Perform - работает
//Complite - завершен
//Stop - остановлен
//Schedule - запланирован
//WaitPerform - компилится
Выдал статус Newbie
Я так понимаю он выдается до компиляции на новые шаблоны.
 

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
13 492
Благодарностей
5 082
Баллы
113
Видимо да, мне такой ранее не встречался или нововведеный
А можно сделать следующее?

1) Прервать выполнение шаблона
2) Нажать Старт
3) Установить точное значение выполнений.
 

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
13 492
Благодарностей
5 082
Баллы
113
Если потоки запущены и мы их прерываем, то никак нельзя узнать активные потоки.

TaskHelper.GetStatus показывает Stop
TaskHelper.GetNumberOfTriesпоказывает 0

Хотя в проекте могут быть не завершенные потоки. На сколько мне известно нету метода который бы позволял получить активные потоки, может можно косвенно узнать о запущенных потоках?

____
UPD. Уже исправили
 
Последнее редактирование:
Регистрация
05.06.2019
Сообщения
570
Благодарностей
446
Баллы
63
Если потоки запущены и мы их прерываем, то никак нельзя узнать активные потоки.
Хотя в проекте могут быть не завершенные потоки. На сколько мне известно нету метода который бы позволял получить активные потоки, может можно косвенно узнать о запущенных потоках?
Создание/Уничтожение потока не быстрая операция. Созданные потоки похожи на бесконечный автоматы, если их отправить восвояси (не держа с ними связь на поводке, то они могут засесть в памяти), в то время, как главный поток уже закончил свою работу.

Все конечно индивидуально, но что-то да можно придумать...
Можно создать надстройку над пулом (ThreadPoolWorker), в котором есть свойства: Success, Completed и Exception.

Главный поток запускает метод:
C#:
public void Start(object state)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadExecution), state);
}
и ожидает асинхронной операции:
C#:
public void Wait()
{
    while (Completed == false) //если операция не закончилась, ждать...
    {
        Thread.Sleep(100);
    }

    if(Exception != null)      //если операция закончилась, проверить исключение...
    {                          //если возникло исключение, сделать проброс, чтобы отловить возникшую проблему...
        throw Exception;
    }
}
Метод обратного вызова:
C#:
private void ThreadExecution(object state)
{
    try
    {
        action.Invoke(state);
        Success = true;         //закончилась успешно
    }
    catch (Exception ex)
    {
        Exception = ex;         //записать тип исключения
        Success = false;        //закончилась неуспешно
    }
    finally
    {
        Completed = true;   //асинхронная операция завершила свое выполнение
    }
}
Реализовав диспетчер ожидания события или DispatcherTimer + CancellationTokenSource можно отменить операцию.

ThreadPool, минусы:
* Все потоки в пуле потоков являются фоновыми. В случае завершения работы всех приоритетных потоков в процессе работа всех фоновых потоков тоже останавливается. Сделать поток из пула приоритетным не удастся.

* Нельзя изменять приоритет или имя находящего в пуле потока. Все потоки в пуле представляют собой потоки многопоточного апартамента (multi-threaded apartment — МТА), а многие СОМ-объекты требуют использования потоков однопоточного апартамента (single-threaded apartment — STA).

* Потоки в пуле подходят для выполнения только коротких задач. Если необходимо, чтобы поток функционировал все время (как, например, поток средства проверки орфографии в Word), его следует создавать с помощью класса Thread.

* Нельзя создать поток с фиксированной идентичностью, чтобы можно было прерывать его или находить по имени.
Источник: professorweb.ru/my/csharp/thread_and_files/1/1_16.php

Тогда на помощь class Thread или для более гибкой работы с потоками есть class Task, который может использовать так называемое продолжение (ContinueWith), ну и нововведение ValueTask.

По теме:
Обработка исключения ThreadInterruptedException
Справка: приостановка и прерывание потоков
Дополнительно: Прерывание потока

Итог: Из выше перечисленного, видно: Технологий много, какую из них выбрать непонятно.
П.С. Здесь нужна помощь просветленных.

Мне с моим багажом знаний (а он еще очень маленький))), не потянуть.
2C09FFeJO4o[3].jpg


Приходит на ум:
1) Реализация диспетчер ожидающего событие:
C#:
public async static void WaitEvent()
{
    await Task.Run(() =>
    {
       // code
    });
}
готовый вариант от @Zymlex :ay:

2. Создание дополнительного потока, который выполняет основную логику кубика C#:
Предположим, необходимо вызвать метод:
C#:
private void DoSomething()
{ ... }
Отработка логики:
C#:
ThreadStart asyncMethod = new ThreadStart(DoSomething);
Thread thread = new Thread(asyncMethod);
thread.Start();
или реализовав оболочку для дополнительного потока, логика: Success, Completed, Exception и CancellationToken.

3. Завершение операции или отмена.
Главный поток ожидает завершение операции второго потока или ждет сигнал от диспетчера (ожидающий событие об отмене и оповещает главный поток о немедленном прекращение), а далее сохранение состояния второго потока.

Вроде похоже на правду и выглядит как, кучер с упряжкой лошадей, где все лошадки под контролем.
 
Последнее редактирование:

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
13 492
Благодарностей
5 082
Баллы
113

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
13 492
Благодарностей
5 082
Баллы
113
В 7.3.0.0 Добавили возможность получить кол-во активных потоков. Вот код:
C#:
var Id = Guid.Parse(project.TaskId);
int currentTaskThreadsById = ZennoPoster.GetThreadsCount(Id);
return currentTaskThreadsById;
 

semafor

Client
Регистрация
27.12.2016
Сообщения
288
Благодарностей
385
Баллы
63
Доброго дня.
Во-первых, спасибо DmitryAk за тему и идею.
Когда набрел на тему — добавил туда свой метод, для получения даты следующего запуска нужных шаблонов работающих в планировщике:
C#:
/// <summary>
/// получаем дату следующего запуска
/// </summary>
/// <param name="TaskName"></param>
/// <returns></returns>    
public static string NextSheduleDate(string TaskName)
{
    string sid = TaskHelper.GetTaskId(TaskName);
    var id = Guid.Parse(sid);
    var taskInfo = ZennoPoster.GetTaskInfo(id);
    string nextStartInfo = Regex.Match(taskInfo,@"(?<=<NextScheduleTime>).*?(?=</NextScheduleTime>)").Value;
    return nextStartInfo;
         
}
И какое-то время юзал все это в нескольких шабах — строки с датами (в ZennoPoster.TasksList они представлены в формате MM/dd/yyyy hh:mm:ss) парсились в DateTime, все крутилось-вертелось. Потом шаблоны в которых это использовалось стали неактуальны, и я какое-то время не использовал фишку.

А сегодня понадобилось проверить состояние одного шаба (и получить дату его след. запуска) пред выполнением действий в другом. Ну дело-то не хитрое, закинул класс в общий код, накалякал такой кубик:
C#:
//IFormatProvider
CultureInfo provider = CultureInfo.InvariantCulture;
//Имя шаблона
string taskname = "TemplateName";          
//Получили дату следующего запуска
string nextstart = TaskHelper.NextSheduleDate(taskname);
//парсим дату след. запуска
DateTime dttmpl = DateTime.ParseExact(nextstart,"MM/dd/yyyy hh:mm:ss", provider);
И приготовился почивать на лаврах, но...
В результате выполнения кубика в PM получил ошибку «Выполнение действия CSharp OwnCode. Строка не распознана как действительное значение DateTime.»
При этом строка вида string nextstart = "01/18/2021 23:17:22" по-прежнему замечательно парсится в DateTime через ParseExact, получение в строку значения из ZennoPoster.TasksList тоже происходит без ругани, даже пробовал через переменную проекта прогнать значение. На выходе все равно та же ошибка. PM перегружал, перебирал разные варианты CultureInfo — ничего не помогло.
В результате экспериментов я ошибку обошел таким образом:
C#:
CultureInfo provider = CultureInfo.InvariantCulture;
//Имя шаблона
string taskname = "TemplateName";
//Получили дату следующего запуска и разобрали ее на время и дату
string[] nextstart = TaskHelper.NextSheduleDate(taskname).Split(' ');
//получили DateTime
DateTime dttmpl = DateTime.ParseExact(nextstart[1],"T", provider);
Но! Вопрос остался — а что такого-эдакого присутствует в возвращаемой строке (реальный пример: 01/18/2021 23:17:28 ), точнее в ее части 01/18/2021, что приводит компилятор в замешательство? Или это только у меня PM выёживается?
Версия ZP 7.1.5, переходить на более свежие после просмотра веток с багами, пока не решался.
 
  • Спасибо
Реакции: phoenixs

Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
5 883
Благодарностей
3 041
Баллы
113
В результате выполнения кубика в PM получил ошибку «Выполнение действия CSharp OwnCode. Строка не распознана как действительное значение DateTime.»
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.

В последних версиях постера, по умолчанию ru-ru или en-us в зависимости от языка постера, но это можно изменить:
 
Последнее редактирование:

semafor

Client
Регистрация
27.12.2016
Сообщения
288
Благодарностей
385
Баллы
63
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.
Хм... Дык я ведь вроде явно указывал — CultureInfo.InvariantCulture, куда уж универсальнее? При этом вот такой варниант прекрасно работал:
C#:
CultureInfo prov = CultureInfo.InvariantCulture;
string dtstr = "01/18/2021 12:22:22";
string frmt = "MM/dd/yyyy hh:mm:ss";
DateTime dt = DateTime.ParseExact(dtstr, frmt, prov);
А такой выдавал приведенную выше ошибку:
C#:
CultureInfo prov = CultureInfo.InvariantCulture;
string taskname = "TaskName";
string dtstr = TaskHelper.NextSheduleDate(taskname).ToString();
string frmt = "MM/dd/yyyy hh:mm:ss";
DateTime dt = DateTime.ParseExact(dtstr, frmt, prov);
UPD. После перезагрузки системы заработали оба варианта. Ять, вечер выбросил на гребанные эксперименты!!!
P.S. А может это РКН своим блоком все починил )))
 
  • Спасибо
Реакции: djaga

ZSharp

Client
Регистрация
29.09.2013
Сообщения
343
Благодарностей
83
Баллы
28
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.

В последних версиях постера, по умолчанию ru-ru или en-us в зависимости от языка постера, но это можно изменить:
Смотрю не только в этой теме о локалях.
Всегда (где-то в начале шаблона) указываю инвариант вот так
C#:
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Это теперь не работает? И нужно обязательно в настройках указывать?
 

Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
5 883
Благодарностей
3 041
Баллы
113
  • Спасибо
Реакции: ZSharp

Bas

Client
Регистрация
15.12.2013
Сообщения
589
Благодарностей
242
Баллы
43
Подскажите, а как получить именно заданное максимальное количество потоков, а не текущее активное?
C#:
ZennoPoster.GetThreadsCount(name_project);
Этот метод возвращает количество активных потоков, есть такой же для получения заданного максимального числа потоков?
 

Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
5 883
Благодарностей
3 041
Баллы
113

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