【发布时间】:2014-02-21 20:14:18
【问题描述】:
我对连接池的理解是;如果连接字符串完全相同,那么我们重用连接而不是建立新连接。
我的问题是我为并行处理创建了许多线程。在这个“虚拟”程序中,我创建了 500 个线程并让 ThreadPool 函数处理这些线程。
步骤如下:
每个线程在 SQL 中创建一个更新表。 (说明更新的时间戳)
然后线程休眠 1 到 10 秒(随机)。
最后,线程在 SQL 中进行另一次更新(说明结束时间的时间戳)
-
然后线程退出
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"Max Pool Size=200;Pooling=True;
但这只是将问题推迟到稍后阶段,因为连接池将达到 200 并且超时将在某个时候达到。
问题:为什么要一遍又一遍地创建连接,而不是重复使用连接池中的一个?
非常感谢任何提示、提示或建议。
【问题讨论】:
-
您正尝试在 100 个连接上运行 500 个并发进程。你认为这怎么可能? SQL 连接池不能在同一连接上同时运行两个(或三个或四个)不同的命令。这不是连接池的意思。
-
无论如何,您的网络连接实际上不太可能有能力跟上那么多并发请求。你几乎肯定不应该有那么多线程或那么多连接,除非这是一个有大量资源支持的大型服务器。
-
这是个好问题。您可以在使用后安全地处理连接。您对连接对象的使用仅在单个呼叫期间使用。池应该可以正常工作。从池中获取连接会超时。如果没有可用的连接,它不会明显失败。如果所有连接都保持一小段时间,这应该可以完美地工作。调查,为什么连接会保持很长时间。
-
无关:您正在使用迷信的处置模式。处理 3 次而不是 1 次没有任何好处。
标签: c# sql-server multithreading connection-pooling invalidoperationexception