簡體   English   中英

Scala中的異步IO與期貨

[英]Asynchronous IO in Scala with futures

假設我從一些URL下載了一個(可能很大的)圖像列表。 我正在使用Scala,所以我要做的是:

import scala.actors.Futures._

// Retrieve URLs from somewhere
val urls: List[String] = ...

// Download image (blocking operation)
val fimages: List[Future[...]] = urls.map (url => future { download url })

// Do something (display) when complete
fimages.foreach (_.foreach (display _))

我對Scala有點新意,所以對我來說這看起來仍然有些神奇:

  • 這是正確的方法嗎? 任何替代品,如果不是?
  • 如果我要下載100個圖像,這會一次創建100個線程,還是會使用線程池?
  • 最后一條指令( display _ )是否會在主線程上執行,如果沒有,我該如何確定它?

謝謝你的建議!

在Scala 2.10中使用Futures。 他們是Scala團隊,Akka團隊和Twitter之間的聯合工作,以實現更加標准化的未來API和跨框架使用的實現。 我們剛剛發布了一份指南: http//docs.scala-lang.org/overviews/core/futures.html

除了完全非阻塞(默認情況下,盡管我們提供了管理阻塞操作的能力)和可組合之外,Scala的2.10期貨還帶有一個隱式線程池來執行您的任務,以及一些管理超時的實用程序。

import scala.concurrent.{future, blocking, Future, Await, ExecutionContext.Implicits.global}
import scala.concurrent.duration._

// Retrieve URLs from somewhere
val urls: List[String] = ...

// Download image (blocking operation)
val imagesFuts: List[Future[...]] = urls.map {
  url => future { blocking { download url } }
}

// Do something (display) when complete
val futImages: Future[List[...]] = Future.sequence(imagesFuts)
Await.result(futImages, 10 seconds).foreach(display)

上面,我們首先導入一些東西:

  • future :創造未來的API。
  • blocking :用於托管阻止的API。
  • Future :未來的伴侶對象,其中包含許多有用的期貨收集方法。
  • Await :用於阻止未來的單例對象(將其結果傳輸到當前線程)。
  • ExecutionContext.Implicits.global :默認的全局線程池,一個ForkJoin池。
  • duration._ :用於管理超時duration._實用程序。

imagesFuts與您最初的工作基本相同 - 唯一的區別是我們使用托管阻塞blocking 它通知線程池您傳遞給它的代碼塊包含長時間運行或阻塞操作。 這允許池臨時生成新工作程序,以確保永遠不會發生所有工作程序被阻止的情況。 這樣做是為了防止阻塞應用程序中的飢餓(鎖定線程池)。 請注意,線程池還知道托管阻塞塊中的代碼何時完成 - 因此它將在該點刪除備用工作線程,這意味着池將縮減回其預期大小。

(如果您想絕對阻止創建其他線程,那么您應該使用AsyncIO庫,例如Java的NIO庫。)

然后我們使用Future伴隨對象的集合方法將imagesFutsList[Future[...]]轉換為Future[List[...]]

Await對象是我們如何確保在調用線程上執行display的方法Await.result只是強制當前線程等待,直到傳遞它的未來完成。 (這在內部使用托管阻止。)

val all = Future.traverse(urls){ url =>
  val f = future(download url) /*(downloadContext)*/
  f.onComplete(display)(displayContext)
  f
}
Await.result(all, ...)
  1. 在2.10中使用scala.concurrent.Future,現在是RC。
  2. 它使用隱式ExecutionContext
  3. 新的Future doc明確指出onComplete(和foreach)可以在值可用時立即進行評估。 老演員Future做同樣的事情。 根據您的要求顯示,您可以提供合適的ExecutionContext(例如,單個線程執行程序)。 如果您只是希望主線程等待加載完成,則遍歷會為您提供等待的未來。
  1. 是的,對我來說似乎很好,但是你可能想要研究更強大的twitter-utilAkka Future API(Scala 2.10將有這種風格的新Future庫)。

  2. 它使用線程池。

  3. 不,它不會。 您需要使用GUI工具包的標准機制(Swing的SwingUtilities.invokeLater或SWT的Display.asyncExec )。 例如

     fimages.foreach (_.foreach(im => SwingUtilities.invokeLater(new Runnable { display im }))) 

暫無
暫無

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

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