2

Мое понимание пула соединений; если строка соединения точно такая же, то мы повторно используем соединение вместо создания нового соединения.Пул соединений - один процесс - много потоков

Моя проблема в том, что я создаю много потоков для параллельной обработки. В этой «фиктивной» программе я создаю 500 потоков и позволяю функции ThreadPool обрабатывать потоки.

Шаги:

  1. Каждая нить сделать таблицу обновления в SQL. (Указание метки времени для обновления)

  2. Затем поток спит от 1 до 10 секунд (случайный).

  3. В конце нить делает еще одно обновление в SQL (с указанием метки времени для конечного времени)

  4. Затем нить выхода

    class Program 
    { 
        static void Main(string[] args) 
        { 
         int numberOfThreads = 150; 
    
         ThreadPool.SetMinThreads(numberOfThreads, numberOfThreads); 
         ThreadPool.SetMaxThreads(numberOfThreads, numberOfThreads); 
    
         List<Int64> chunkList = new List<Int64>(); 
    
         int maxNumberOfChunks = 500; 
         for (int i = 1; i < maxNumberOfChunks; i++) 
         { 
          chunkList.Add(i); 
         } 
    
         foreach (Int64 chunk_id in chunkList) 
         { 
          ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWorker), new arguments { chunk_id = chunk_id }); 
         } 
         Console.ReadLine(); 
    
        } 
        static void ThreadWorker(Object stateInfo) 
        { 
         arguments arguments = (arguments)stateInfo; 
    
         Console.WriteLine("Chunk # : {0} is set to START", arguments.chunk_id); 
         UpdateSQLdb(arguments.chunk_id, DateTime.Now, null, null, "START", null, null); 
    
         Random random = new Random(); 
         int mseconds = random.Next(1, 10) * 1000; 
         System.Threading.Thread.Sleep(mseconds); 
         Console.WriteLine("Chunk # : {0} is sleeping for {1} sec.", arguments.chunk_id, mseconds); 
    
         Console.WriteLine("Chunk # : {0} ist set to END", arguments.chunk_id); 
         UpdateSQLdb(arguments.chunk_id, null, DateTime.Now, null, "END", null, null); 
        } 
        struct arguments 
        { 
         public Int64 chunk_id; 
        } 
    
        static void UpdateSQLdb(Int64 CHUNK_ID, DateTime? START_TS = null, DateTime? END_TS = null, Enum CHUNK_STATUS = null, string error_messages = null, byte? NEW_CALCULATION_ATTEMPTS = null, byte? NEW_POSTPROCESS_ATTEMPTS = null) 
        { 
         using (SqlConnection conn = new SqlConnection("Data Source=C55S01;Initial Catalog=MCS_BATCH;Integrated Security=SSPI;Asynchronous Processing=True")) //Timeout=60;Max Pool Size=200;Pooling=True; 
         { 
          int result = -1; 
          conn.Open(); //<-- Each time I open a connection. It creates a new instead of reusing one from the ConnectionPool 
    
          try 
          { 
           using (SqlCommand cmd = new SqlCommand("TEST.UpdateSQL", conn)) 
           { 
            cmd.CommandTimeout = 300; 
            cmd.CommandType = System.Data.CommandType.StoredProcedure; 
    
            cmd.Parameters.Add("@CHUNK_ID", SqlDbType.BigInt, 15).Value = CHUNK_ID; 
            cmd.Parameters.Add("@START_TS", SqlDbType.DateTime2, 7).Value = START_TS; 
            cmd.Parameters.Add("@END_TS", SqlDbType.DateTime2, 7).Value = END_TS; 
            cmd.Parameters.Add("@ERR_MESSAGE", SqlDbType.VarChar).Value = error_messages; 
            cmd.Parameters.Add("@ReturnValue", System.Data.SqlDbType.Int, 4).Direction = System.Data.ParameterDirection.ReturnValue; 
    
            try 
            { 
             result = cmd.ExecuteNonQuery(); 
    
             int return_value = (int)cmd.Parameters["@ReturnValue"].Value; 
             if (return_value != 0) 
             { 
              Console.WriteLine("1. Error in running TEST.UpdateSQL, return value is : {0}", cmd.Parameters["@ReturnValue"].Value); 
             } 
            } 
            catch (SqlException ex) 
            { 
             UpdateSQLdb(CHUNK_ID, null, DateTime.Now, null, ex.Message.ToString(), null, null); 
             Console.WriteLine("2. Error executing TEST.UpdateSQL : {0}", ex); 
            } 
           } 
          } 
          catch (Exception ex) 
          { 
           Console.WriteLine("3.Error in TEST.UpdateSQL : {0}", ex); 
           throw; 
          } 
          if (conn.State == ConnectionState.Open) 
          { 
           Console.WriteLine("Closing connection...."); 
           conn.Close(); 
          } 
          conn.Dispose(); 
         } 
        } 
    } 
    

    }

Моя проблема что я получил System.InvalidOperationException был необработанным (Истекло время ожидания ожидания). Период ожидания истекает до получения соединения из пула. Возможно, это произошло из-за того, что все объединенные соединения использовались и был достигнут максимальный размер пула.)

Я отслеживал количество подключений на SQL-сервере и быстро добирался до 100 подключений соединений в пуле)

Если попытались добавить эти параметры в строке соединения: Timeout = 60" Максимальный размер пула = 200; Pooling = True;

Но это будет просто отложить проблему на более поздний этап, потому что пул соединений достигнет 200, а таймаут будет достигнут в какой-то момент.

Вопрос: Почему соединения создаются снова и снова, вместо повторного использования одного из пула соединений?

Подсказка, советы и рекомендации приветствуются.

+0

Вы пытаетесь запустить 500 одновременных процессов на 100 соединениях. Как вы думаете, что это возможно? Пул соединений SQL не может одновременно запускать две (или три или четыре) команды в одном и том же соединении. Это не то, что связывает объединение. – EkoostikMartin

+0

Маловероятно, что ваше сетевое подключение действительно имеет возможность идти в ногу с таким количеством одновременных запросов.Вы почти наверняка не должны иметь столько потоков или много соединений, если это не большой сервер с большим количеством ресурсов, поддерживающих его. – Servy

+1

Это хороший вопрос. После использования вы безопасно удаляете соединение. Использование вами объекта соединения используется только на время одного вызова. Объединение должно работать нормально. При подключении к пулу зависит от тайм-аута. Это не означает, что соединение отсутствует. Это должно работать отлично, если все соединения хранятся в течение небольшого промежутка времени. Исследуйте, почему соединения хранятся в течение длительного времени. – usr

ответ

1

Это именно то, что вы просили. Он использует соединения из пула, но вы дали ему слишком много работы. Если у вас есть 500 потоков и 200 подключений, каждый поток не может иметь соединение. Вероятно, у вас должно быть столько связей, сколько потоков.

Если у вас еще больше работы (все 500 потоков заняты), вам необходимо либо вернуть ошибку потребителю, либо иным образом активировать ввод в ваше приложение.

Смежные вопросы