2017-05-31 42 views
0

我有一個類似的代碼:未來呼喚Scala中的理解 - 我如何順序處理它們?

for (n <- 1 to 1000) { 
    someFuture map { 
    // some other stuff 
} 

這是一個代碼基本部件和工作正常。但是,somefuture會對數據庫執行一些查詢,並且數據庫不能並行接收多個查詢,而這正是之前發生的情況(它會產生大量執行somefuture的線程,正如人們所期望的那樣)。理想情況下,我希望順序執行(即當n = 1時調用someFuture,做一些處理,當n = 2時調用someFuture,做一些處理等)。我想過使用一些阻止方法(從Await),但這發生在一個演員內部,所以阻止不是一個好主意。另一個想法是創建一個固定的線程池爲這個特定的未來呼叫,但聽起來像矯枉過正。我該怎麼做呢?

更新:我發現this answer,它建議創建一個固定的線程池,因爲我認爲。不過,這是做這件事的正確方法嗎?

回答

0

一種方法是將消息發送給處理數據的參與者。 由於actor一個接一個地處理消息,因此您會按順序並行執行查詢。

for (n <- 1 to 1000) { 
    someFuture map { 
     x => actor ! x 
    } 
} 
+0

查詢發生在'someFuture'中,因此'''''''''''''Future'裏面有什麼並不重要,對吧? –

+0

是的,如果查詢在someFuture中運行,那麼它意味着即使在涉及scala的for comprehension塊之前,所有的查詢執行都已被觸發。因此,在你的情況下,你必須在理解塊之前將查詢發送給你的演員。 –

1

您想要映射或平面化單個未來。

scala> val f = Future(42) 
f: scala.concurrent.Future[Int] = Future(Success(42)) 

scala> (1 to 10).foldLeft(f)((f,x) => f.map(i => i + 1)) 
res1: scala.concurrent.Future[Int] = Future(<not completed>) 

scala> res1 
res2: scala.concurrent.Future[Int] = Future(Success(52)) 

scala> (1 to 10).foldLeft(f)((f,i) => { 
    | println(i) 
    | f.map(x => x+i) }) 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
res4: scala.concurrent.Future[Int] = Future(<not completed>) 

scala> res4 
res5: scala.concurrent.Future[Int] = Future(Success(97)) 
+0

此代碼不是堆棧安全的。如果一些期貨很大,你會得到'StackOverflowError'。 – simpadjo

+0

@simpadjo你嘗試過什麼?對我來說,'(1到Int.MaxValue)'耗盡堆,而不是堆棧。 –

+0

這是一篇很好的文章,涵蓋期貨堆垛安全問題https://alexn.org/blog/2017/01/30/asynchronous-programming-scala.html#h3-3。我也在生產中面對它。 – simpadjo

0

可能理想的長期處理方法是使用連接池的數據庫訪問層。大多數框架如play或slick都有處理這種情況的首選方式,或者如果您想單獨使用,DBCP可能是一個不錯的選擇。我認爲大多數應該有一個「自然」的方法來限制連接數量到一個固定的大小,如果沒有連接池可用,這會限制你的並行性。

除了像這樣引入其他一些依賴關係之外,使用線程池執行上下文是您提到的方法。這並不過分;這是非常普遍的,並且比其他任何處理方式都要少得多。

+0

我已經完成了多個EC,所以我不想說它不可行,但對於鏈式執行的簡單用例,我沒有看到future.map或類似的優勢,這意味着在運行時未來完成。根據使用情況,工作分配的方式可能會有很大差異。 –