Имеется программа Windows service, написанная на C#, которая периодически получает набор данных у стороннего web-cервиса, обрабатывает их и записывает в базу данных. Изначально не подразумевалась последовательная загрузка массивов данных. Сначала грузится один набор, потом следующий и т.д. Но со временем объём загружаемых данных и кол-во наборов увеличилось и возникла необходимость загружать их в параллельном режиме. Загрузка одного набора данных стала занимать более часа. Если говорить вкратце, то требуется запуск метода одного и того же класса с различными параметрами в многопоточном режиме. Каждый поток должен запускаться в изолированном режиме и не должен каким-либо образом влиять на одновременное выполнение других аналогичных потоков. Параллельно запускаемые потоки никак между собой не взаимодействуют. Т.е. необходимо чтобы каждый поток работал только со своими экземплярами данных и никак не мог испортить значения переменных, используемых другим потоком.
Грубо говоря есть некий класс DataMultiLoader, содержащий метод Load_and_Export
public class DataMultiLoader
{
public DataMultiLoader(ServiceLogger p_svLogger)
{
svLogger = p_svLogger;
cMTExporter = new Farelogix.MTExport.FQ_Exporter();
}
public void Load_and_Export(eProviders p_Provider, int p_nRRKey, RoutesLoadScheduler p_RScheduler)
{
// здесь выполняется много работы с вызовом методов других классов, в том числе и статических
...
}
}
Отдельная процедура LoadMultiThreading, которая вызывается по таймеру, должна запускать Load_and_Export из класса DataMultiLoader в рамках отдельного изолированного потока.
private void LoadMultiThreading(eBookingProviders p_Provider, int p_nRRKey) {
DataMultiLoader amdLoader = new DataMultiLoader(amdLogger);
...
Thread amdThread;
ThreadStart thStart;
thStart = delegate () { amdLoader.Load_and_Export(p_Provider, nSelectedRRKey, oRScheduler); };
amdThread = new System.Threading.Thread(thStart);
amdThread.Priority = ThreadPriority.AboveNormal;
amdThread.IsBackground = true;
amdThread.Start();
...
}
Я просмотрел теоретические материалы по данной теме и выяснил, что в многопоточных приложениях существует проблема состязания за ресурсы, когда один поток портит данные другого.
Что надо добавить в существующий код, чтобы сделать его потоко безопасным?
Использование локальных блокировок данных с конструкциями типа
lock(lockObj) {
// синхронизируемые операторы
}
является неприемлемым из-за большого объёма существующего кода. По-хорошему здесь не нужна какая-либо синхронизация изменения данных, а нужна полная изолированность, как если бы процедура Load_and_Export запускалась в рамках отдельного процесса.
Можно ли достичь нужного результата если оформить класс DataMultiLoader следующим образом?
[Synchronization]
public class DataMultiLoader: ContextBoundObject
{
...
public void Load_and_Export(eProviders p_Provider, int p_nRRKey, RoutesLoadScheduler p_RScheduler)
{
...
}
}
Не будет ли в этом случае один поток, вызвавший Load_and_Export, ждать завершения этого же метода, вызванного ранее другим потоком из-за его полной блокировки ?
ThreadLocal. – Roman-Stop RU aggression in UA Jun 15 '21 at 15:49Вы предлагаете сделать отдельный exe-модуль- да. Что касается вопроса про то, как работает Synchronization, то его лучше задать отдельно. Это простой сфокусированный вопрос, и на него, уверен, здесь дадут ответ специалисты. Я оформил это в виде отдельного вопроса https://ru.stackoverflow.com/questions/1295814/%d0%9a%d0%b0%d0%ba-%d0%b2-net-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0%d0%b5%d1%82-%d0%b0%d1%82%d1%80%d0%b8%d0%b1%d1%83%d1%82-synchronization-%d0%b2-%d1%81%d0%b2%d1%8f%d0%b7%d0%ba%d0%b5-%d1%81-contextboundobject – Roman-Stop RU aggression in UA Jun 16 '21 at 09:39что закладывается в понятие разделяемых данных- это любые данные, к которым имеют доступ два (или больше) потока. Если говорить о экземплярах, которые созданы в функции и не сохраняются в глобальных (статических) переменных и не сохраняются в объектах, к которым имеют доступ разные потоки, то они не разделяемые, ведь к ним только один поток может получить доступ. – Roman-Stop RU aggression in UA Jun 16 '21 at 12:56