当前位置: 首页 > 知识库问答 >
问题:

连接池 – 一个进程 – 多个线程

司徒宏远
2023-03-14

我对连接池的理解是;如果connectionstring完全相同,那么我们重用该连接,而不是建立新的连接。

我的问题是,我正在为并行处理创建许多线程。在这个“虚拟”程序中,我创建了500个线程,并让线程池函数处理这些线程。

步骤是:

> < li>

每个线程在SQL中创建一个更新表。(说明更新的时间戳)

然后线程Hibernate1到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();
        }
    }
}

}

我的问题是我得到一个系统。无效操作异常未处理 (超时已过期。从池中获取连接之前经过的超时期限。这可能是因为所有池连接都在使用中,并且已达到最大池大小。

我监控了SQL server上的连接数,它很快达到100个连接(这是池中默认的最大连接数)

如果尝试将这些参数添加到连接字符串:Timeout=60 "最大池大小= 200;Pooling = True

但是这只是将问题推迟到以后的阶段,因为连接池将达到200,超时将在某个点达到。

问:为什么一遍又一遍地创建连接,而不是重用连接池中的连接?

非常感谢任何暗示、提示或建议。

共有1个答案

束研
2023-03-14

它正在做你要求它做的事情。它使用了池中的连接,但你给了它太多的工作。如果你有500个线程和200个连接,每个线程不能有一个连接。您可能应该拥有和线程一样多的连接。

如果还有更多工作要做(所有 500 个线程都处于繁忙状态),则必须向使用者返回错误或以其他方式限制应用程序中的输入。

 类似资料:
  • 问题内容: 我正在创建一个多线程应用程序。但是,当我有一个为所有线程服务的连接对象时,我的应用程序遇到了许多意外行为。 我处于两难境地。我应该让每个线程创建,使用和处置其自己的连接对象还是应该使用连接池? 我已经尝试过连接池,这会使应用程序痛苦地洗澡。但是,我的直觉是,如果让每个线程创建自己的连接对象,则可能会出现“连接过多”错误。 请让我知道是否有任何方法可以帮助您。 问候。 问题答案: 无论线

  • 问题内容: 在Java中拥有多个线程池的优缺点是什么?我已经看过代码,其中有多个线程池用于不同的“类型”任务,而且我不确定它是更好的设计还是只是开发人员感到懒惰。一个示例是将ScheduledThreadPoolExecutor用于定期执行的任务或具有超时的任务,而将另一ThreadPoolExecutor用于其他任务。 问题答案: 具有单独的专用线程池的目的是,使活动不会因线程不足而被饥饿,因为

  • 给stackoverflow社区的人们。我正在寻找一些帮助,以解决HikariCP连接池面临的问题。 高级:我正在尝试使用线程池创建多个线程,我的计划是为每个工作线程提供独立于HikariCP的连接,但HikariCP所做的是在多个线程之间共享一个公共连接。我正在使用 以检索DB连接。现在,当我关闭一个连接时,我在其他线程中看到问题,说连接关闭了,线程正在处理的批次记录被丢弃。 以下是我的日志文件

  • 我有一个Spring Boot 1.5应用程序与Spring Batch 3.0.7和Java8。我最近收到了一些连接超时,当一个计划作业试图从5个线程开始时,而另一个长时间运行的批处理作业正在运行。似乎有15个线程合并的连接争用。我没有找到任何留档、博客或问题,似乎解决了Spring Batch中线程和池的相关性。 我使用HikariCP有3个连接,每个数据源配置为默认值(10个连接): bat

  • 问题 你创建一个工作者线程池,用来响应客户端请求或执行其他的工作。 解决方案 concurrent.futures 函数库有一个 ThreadPoolExecutor 类可以被用来完成这个任务。 下面是一个简单的TCP服务器,使用了一个线程池来响应客户端: from socket import AF_INET, SOCK_STREAM, socket from concurrent.futures

  • 问题内容: 我在一个由启动子进程的主进程组成的项目中使用PostgreSQL和SQLAlchemy。所有这些过程都通过SQLAlchemy访问数据库。 我遇到了可重复的连接失败:前几个子进程正常工作,但是过一会儿出现连接错误。这是MWCE: 在我的系统上(PostgreSQL 9.6,SQLAlchemy 1.1.4,psycopg2 2.6.2,Python 2.7,Ubuntu 14.04),