Я создал класс с методом, который вызывается разными потоками (вне класса). Перед вызовом метода потоки обновляют свой собственный набор параметров, обновляя словарь свойств в классе. Я параметризирую метод, выбирая соответствующий элемент из словаря.
Метод содержит различные переменные и выполняет различные вычисления. Если вычисления возвращают определенное значение, метод передает управление одному из нескольких внешних API, ожидает, пока API вернет значение, записывает значение в базу данных и затем завершается.
Я хочу, чтобы каждый вызов метода был полностью независимым - т. Е. Поток A не должен мешать значению переменных в потоке B и наоборот. Мое первоначальное чтение предполагает, что это не модель, используемая для многопоточности в C #, а то, что каждая переменная в методе доступна и обновляется любым потоком - то есть Datarace (? Здесь может использоваться неправильный термин). Блокировка не идеальна для меня, так как время выполнения каждого потока важно. (Если я заблокирую, я понимаю, что потоки будут выполняться последовательно, поскольку они ссылаются на один и тот же метод / переменные).
Я думаю Я добился поведения, которое искал, используя пул потоков в python, хотя могло случиться так, что мне повезло во время моего ограниченного использования!
Возможно ли, чтобы вызовы / потоки методов были полностью независимы друг от друга в C #, как описано выше? Если да, то не могли бы вы указать мне направление, в котором я должен искать?
Большое спасибо.
Обновление: вот выдержка из кода в том, что я пытаюсь сделать, в соответствии с просьбой. Я удалил большую часть кода, который относится к вычислениям, и просто оставил комментарии и то, как разные классы называют потоки и т. Д.
//Websockets sharp on-message event
//Within namespace1.class1
ws.OnMessage += (sender, e) =>
{ //write a whole lot of pricing data to a dictionary ("price dictionary") and identify whether we should re-evealuate our pricing conditions
if (blnReevaluatePricingConditions)
{
nsStrategy.csStrategy objPriceCheck = new nsStrategy.csStrategy();
objPriceCheck.EvaluatePricingConditions(strExchange, strInstrument);
}
}
// within nsStrategy.csStrategy
public void EvaluatePricingConditions(string strExchange = "", string strInstrument = "")
{ //evaluate the pricing conditions (stored in a dictionary ("conditions dictionary")) against the price dictionary
//If conditions evaluate to trade = true, create a list of >1 sets of trade parameters to execute using REST API
nsREST.csREST myRESTObject = new nsREST.csREST();
nsREST.MarketOrder[] MOs = new nsREST.MarketOrder[n]; //n>1 - MOs stands for Market Orders
//Populate list
//...
//Execute by passing the list to a method in the csREST class object just created
myRESTObject.MarketOrder(MOs);
//Wait for completion of REST API calls
//Update db with parameters from MOs list
//End method
}
//within nsRest.csRest
public void MarketOrder(MarketOrder[] mktOs)
{
//Create a list of exchange methods (i.e. parameters for the exchange APIs)
ExchangeMethod[] lstExchangeMethods = new ExchangeMethod[mktOs.GetUpperBound(0)+1];
//Create a list of objects populted from the JSON the exchanges return
RestReturns[] rstReturn = new RestReturns[mktOs.GetUpperBound(0)+1];
//Populate the lstExchangeMEthods...and call a method passing it the list
rstReturn = threadedExchangeMethod(lstExchangeMethods);
}
public RestReturns[] threadedExchangeMethod(ExchangeMethod[] lstExchangeMethods)
{ //Executes the ExchangeMethods passed to it simultaneously, then waits for response from each.
List<Thread> lstThreads = new List<Thread>();
RESTGlobalVars.ExchangeMethodList = lstExchangeMethods;
//Now add a new thread to the list and start it with the parameters below
for (int i = 0; i <= lstExchangeMethods.GetUpperBound(0); i++)
{
lstThreads.Add(new Thread(ThreadedExchangeMethodExecution));
Thread.Sleep(5); //allow a tiny bit of time for the first thread to update to completed status
lstThreads[lstThreads.Count() - 1].Start();
}
}
private void ThreadedExchangeMethodExecution()
{
//Loop through the class-level list of exchangemethod parameters, set blnCompleted to true so it's not picked again by the next thread and call the ExchangeMethods method with the parameters
for (int i = 0; i <= RESTGlobalVars.ExchangeMethodList.GetUpperBound(0); i++)
{
if (RESTGlobalVars.ExchangeMethodList[i].Completed == false)
{
RESTGlobalVars.ExchangeMethodList[i].Completed = true;
RestReturns rstResponse = ExchangeMethods(RESTGlobalVars.ExchangeMethodList[i].Exchange, RESTGlobalVars.ExchangeMethodList[i].Method, RESTGlobalVars.ExchangeMethodList[i].Parameters);
rstResponse.Exchange = RESTGlobalVars.ExchangeMethodList[i].Exchange;
RESTGlobalVars.ExchangeMethodList[i].Response = rstResponse;
}
}
}
public class ExchangeMethod
{
public string Exchange { get; set; }
public string Method { get; set; }
public string Parameters { get; set; }
public Boolean Completed { get; set; }
public RestReturns Response { get; set; }
}
public class MarketOrder
{
public string StrategyName { get; set; }
public string Exchange { get; set; }
public string Instrument { get; set; }
public string BuyOrSell { get; set; }
public double VolumeInUSD { get; set; }
}
public static class RESTGlobalVars
{
public static ExchangeMethod[] ExchangeMethodList { get; set; }
public static Dictionary<string, RateLimits> dtRateWait = new Dictionary<string, RateLimits>();
}
Что касается рабочего процесса, я получаю сообщение websocketssharp (я полагаю, что это фоновый поток). Это может быть один из нескольких каналов веб-сокетов, каждый из которых содержится в своем собственном пространстве имен и классе, и каждый из которых продолжает свою логику. Я оцениваю сообщение, помещаю цены в него в словарь и затем вызываю метод для оценки цен, чтобы определить, следует ли нам торговать. Затем этот метод выполняет некоторые вычисления и (если применимо) создает список торговых параметров, затем вызывает метод MarketOrder, передавая ему список параметров. Параметры рыночного ордера превращаются в аналогичный (слегка избыточный) список параметров метода обмена, для каждого из которых «завершенный» параметр имеет значение false, которые записываются в список уровня класса («глобальный»). Затем мы создаем новую тему для каждого элемента в списке. Каждый поток проверяет глобальный список и извлекает первый незавершенный элемент из списка. Он устанавливает для завершенного параметра значение true, а затем выполняет вызов API.
Спасибо тем, кто уже ответил - я читаю ваши предложения ...