Можно ли запустить поток в C # с его собственными переменными, которые не обновляются при последующих вызовах? - PullRequest
0 голосов
/ 28 июня 2018

Я создал класс с методом, который вызывается разными потоками (вне класса). Перед вызовом метода потоки обновляют свой собственный набор параметров, обновляя словарь свойств в классе. Я параметризирую метод, выбирая соответствующий элемент из словаря.

Метод содержит различные переменные и выполняет различные вычисления. Если вычисления возвращают определенное значение, метод передает управление одному из нескольких внешних 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.

Спасибо тем, кто уже ответил - я читаю ваши предложения ...

1 Ответ

0 голосов
/ 28 июня 2018

Все темы зависят в определенной степени. Все они используют один и тот же процесс и рабочий набор памяти. Разница в том, что каждый поток может иметь процессорное время, которое позволяет всем потокам работать одновременно .

Даже если они совместно используют одни и те же данные, совершенно безопасно использовать данные, на которые не ссылается другой поток.

Т.е.: если у вас есть переменные a и b, поток 1 может безопасно обращаться к a, если поток 2 имеет доступ только к b и наоборот.

В вашем случае словарь делится доступом со всеми вашими потоками, даже если все значения, используемые одним потоком, отличаются от другого.

Есть много способов для этого. Одним из них является создание класса, который будет содержать параметры, которые будет использовать поток, и, вероятно, также иметь некоторое свойство, чтобы поток мог сохранять свои результаты (если они есть).

Так что непосредственно перед запуском потоков выясните, каково подмножество данных для каждого из них, и создайте этот класс данных и передайте этот класс потоку, когда вы захотите его запустить. Затем, как только он завершится, вы получите результаты в объектах и ​​сможете делать все, что вам нужно, когда все потоки вернутся в основной поток.

Вот очень простой пример передачи параметра в поток

...