【发布时间】:2021-12-25 08:50:04
【问题描述】:
在一个项目中,我发现了一种特殊的行为,然后使用 ThreadPool 中的线程连接到 MySQL 实例;应用程序冻结了,看起来这是由于MySqlConnection.Open 内部的死锁。当我手动创建线程并运行 Start 方法时,不会发生这种情况。
This project on GitHub 展示了这一点,我想帮助理解它为什么会这样。
- 有两种方法,
TestThreads和TestTask。每个方法执行一个创建/生成/获取 200 个线程的 for 循环,每个线程连接到具有标准MySqlConnection类的 MySQL 8 服务器,休眠 5 秒,然后关闭连接。秒表测量每个方法完成的时间。 -
TestThreads手动创建线程 (new Thread()... thread.Start());在大约 12-14 秒内完成,我没有发现任何问题。 -
TestTask使用ThreadPool.QueueUserWorkItem;由于MySqlConnection.Open内部似乎发生了死锁,它通常根本不会完成
这是运行TestTask的截图:
所有线程都在MySqlConnection.Open 方法中,并停留在那里。他们似乎没有进一步打印一些日志消息 - 没有为我运行 TestTask 生成日志消息。
另一方面,运行 TestThreads 有效,然后我得到我期望的日志消息:
我想了解为什么创建手动线程时 ThreadPool 会失败?为什么 MySqlConnection 在一种情况下会死锁,而在另一种情况下不会?
请注意,由于我们是针对同一个 MySQL 服务器进行测试,因此这不是 MySQL 配置问题。我也看不出它怎么可能是线程池饥饿;我们将 MinThread 设置为 200。另外,由于在 TestTask 的情况下我从来没有得到一个 Console.WriteLine,肯定还有别的东西吗?
【问题讨论】:
-
可能与饥饿有关,因为 ThreadPool 增长速度有限,以及如何处理任务。这可以通过将最小线程池大小设置为较大并查看行为是否/如何变化来验证。 labs.criteo.com/2018/10/…
-
此测试应用程序将 minthreads 设置为 200,但在其他情况下,我尝试将其设置为 1000,没有区别。我在测试项目中将值调整为500,没有区别。
-
你检查过阻塞线程的堆栈跟踪(包括外部代码)吗?您将 min 和 max 设置为 200,如果其他一些代码(可能是 mysqlconnection 或相关的东西)也想要启动任务或线程池线程怎么办?
标签: c# mysql multithreading threadpool mysql-connector