使用multithreading服务的数据库连接池

我有一个.NET 4 C#服务,它使用TPL库进行线程化。 我们最近将其切换为也使用连接池,因为一个连接正在成为处理的瓶颈。

以前,我们使用lock子句来控制连接对象的线程安全性。 当工作备份时,队列将作为任务存在,并且许multithreading(任务)将等待lock子句。 现在,在大多数情况下,线程会更快地等待数据库IO和工作进程。

但是,现在我正在使用连接池,我们遇到了一个新问题。 达到最大连接数(默认值为100)后,如果请求进一步连接,则会超时(请参阅池信息 )。 发生这种情况时,会抛出一个exception,说“连接请求超时”。

我的所有IDisposable都在using语句中,我正在管理我的连接。 这种情况的发生是由于请求的工作量超过了池可以处理的工作量(这是预期的)。 我理解为什么会抛出这个exception,并且我知道处理它的方法。 简单的重试感觉就像一个黑客。 我也意识到我可以通过连接字符串增加超时时间,但这不是一个可靠的解决方案。 在以前的设计中(没有池),工作项将因应用程序内的锁定而处理。

处理此方案以确保处理所有工作的好方法是什么?

另一种方法是在代码周围使用信号量来检索池中的连接(并且希望返回它们)。 sempahore就像一个锁定语句,除了它允许一次配置数量的请求者,而不仅仅是一个。

这样的事应该做​​:

//Assuming mySemaphore is a semaphore instance, eg // public static Semaphore mySemaphore = new Semaphore(100,100); try { mySemaphore.WaitOne(); // This will block until a slot is available. DosomeDatabaseLogic(); } finally { mySemaphore.Release(); } 

您可以通过使用Parallel.ForEach()方法来控制并行度,如下所示:

 var items = ; // your collection of work items var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 100 }; Parallel.ForEach(items, parallelOptions, ProcessItem) 

在这种情况下,我选择将度数设置为100,但您可以选择对当前连接池实现有意义的值。

当然,此解决方案假定您预先拥有一组工作项。 但是,如果您通过某些外部机制(如传入的Web请求)创建新任务,则exception实际上是一件好事。 此时我建议您使用并发队列数据结构,您可以放置​​工作项并在工作线程可用时将其弹出。

最简单的解决方案是将连接超时增加到您愿意在返回失败之前阻止请求的时间长度。 必须有一段时间“太长”。

这有效地将连接池用作具有超时的工作队列。 这比试图自己实现一个容易得多。 您必须检查连接池是否公平(FIFO)。