2

在修改了一种服务方法以使用多线程后,我发现如果多个用户尝试多次请求页面(并调用服务方法),服务器开始抛出“无法获得连接,池耗尽”异常。让我提供一个我的服务类的例子。

class DocumentService {
   def convertToJSON() {
      docs.collect { doc ->
         taskExecutor.submit({
            Document.withNewSession {
                def json = convertDocumentToJSON(doc)
            }
         } as Callable)
      }.collect { it.get() }
   }

   def convertDocumentToJSON(doc){
      def json = [:]
      // ... fill json with data using doc and GORM requests
      evaluateStatus(json)
      return json
   }

   def evaluateStatus(json){
      //... some work using database through GORM
   }
}

我已经为这个问题苦苦挣扎了一个多星期,但我找不到解决方案。我不太了解 Grails 如何处理会话、连接和事务。我的猜测如下。当调用 convertDocumentToJSON 时,它从池中获取连接(4 个用户,每个用户 25 个线程 = 100 个连接),但随后他们需要调用 evaluateStatus 方法,该方法也尝试从池中获取连接以满足自己的需要。但是pool已经用完了,没有一个线程可以释放连接,因为它们都在等待evaluateStatus。所以,有死锁。我试图为评估状态设置支持传播类型,但我得到“池连接已关闭”异常。然后我认为如果我从 convertDocumentToJSON 移动评估状态调用并编写这样的代码,它可能会起作用

def convertToJSON(){
  docs.collect { doc ->
    taskExecutor.submit({
        Document.withNewSession {
            def json = convertDocumentToJSON(doc)
            evaluateStatus(json) // move call from convertDocumentToJSON
        }
      } as Callable)
  }.collect { it.get() }
}

但在这种情况下,我也遇到了同样的错误(池耗尽)。请给我建议我应该在我的代码中修复什么

4

1 回答 1

0

您需要一些东西来限制连接的使用,尝试使用GPars ,例如

import groovyx.gpars.GParsPool

GParsPool.withPool() {
    docs.collect {
        // do your stuff...
    }
}

常见的常规收集方法有 XXXXParallel 版本,例如 collectParallel,您可以使用它来帮助提高性能。

于 2017-05-29T14:46:22.633 回答