簡體   English   中英

在“大”Future.sequence 上被 slick.util.AsyncExecutor 拒絕

[英]rejected from slick.util.AsyncExecutor on "large" Future.sequence

我花了一整天的時間試圖弄清楚如何解決這個問題。

目的是將多個字符串序列插入到表的單個列中。

我有這樣的方法:

case class Column(strings: Seq[String])

def insertColumns(columns: Seq[Column]) = for {
_ <- Future.sequence(columns.map(col => insert(col)))
} yield()

private def insert(column: Column) =
  db.run((stringTable ++= rows)) //slick batch insert

這在一定程度上起作用。 我測試了 2100 列的序列(每列有 100 個字符串),它工作正常。 但是一旦我將列數增加到 3100+,我就有這個錯誤

Task slick.basic.BasicBackend$DatabaseDef$$anon$3@293ce053 rejected from slick.util.AsyncExecutor$$anon$1$$anon$2@3e423930[Running, pool size = 10, active threads = 10, queued tasks = 1000, completed tasks = 8160]

我在幾個地方讀過,做這樣的事情會有所幫助

case class Column(strings: Seq[String])

val f = Future.sequence(columns.map(col => insert(col)))

def insertColumns(columns: Seq[Column]) = for {
_ <- f
} yield()

private def insert(column: Column) =
  db.run((stringTable ++= rows)) //slick batch insert

它不是。

我在insert中嘗試了幾種更改組合

Future.sequence(
rows.grouped(500).toSeq.map(group => db.run(DBIO.seq(stringTable ++= group)))
)
Source(rows).buffer(500, OverflowStrategy.backpressure)
  .via(
    Slick.flow(row => stringTable += row)
  )
  .log("nr-of-inserted-rows")
  .runWith(Sink.ignore)
Source(rows)
.runWith(Slick.sink(1, row => stringTable += row))

我試過了:

  • 不要在我的配置中使用reWriteBatchedInserts=true
  • (dataColumnStringsTable ++= rows).transactionally選項
  • 使用特定的執行上下文來啟用單個線程: implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))嘗試順序執行期貨

除了修改訂閱者以接收和阻止我的消息(字符串序列)並處理隊列消息傳遞端的背壓之外,我沒有任何其他想法。

我正在使用 slick (with alpakka-slick) 3.3.3 / HikariCP 3.2.0 / Postgres 13.2

我的配置是這樣的

slick {
  profile = "slick.jdbc.PostgresProfile$"
  db {
      connectionPool = "HikariCP"
      dataSourceClass = "slick.jdbc.DriverDataSource"
      properties = {
        driver = "org.postgresql.Driver"
        user = "postgres"
        password = "password"
        url = "jdbc:postgresql://"${slick.db.host}":5432/slick?reWriteBatchedInserts=true"
      }
      host = "localhost"
      numThreads = 10
      maxConnections = 100
      minConnections = 1
    }
}

感謝您的幫助。

您不應將Future.sequence與多個元素的 collections 一起使用。 每個Future都是在后台運行的計算。 因此,當您針對 3000 columns的集合運行此命令時:

Future.sequence(columns.map(col => insert(col)))

您一次有效地產生了 3000 個操作。 結果,執行者可能會開始拒絕新任務。

解決方案是使用 Akka Streams 處理輸入集合。 在您的情況下,這意味着從columns (而不是從rows )創建Source 這將確保執行器不會被過多的並行操作所淹沒。 我沒有使用alpakka-slick ,但是查看文檔,解決方案應該如下所示:

Source(columns)
  .via(
    Slick.flow(column => stringTable ++= column.rows) 
  )
  // further processing here

更重要的是,如果“列”來自消息隊列,您甚至可能不需要中間Seq[Column] 您可能只需要定義從隊列中讀取的ColumnSource ,並使用 Slick 流對其進行處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM