純函數(shù)式的并行計算(2)

打破法則:一個微妙的bug
在上篇博文的實現(xiàn)中篷店,實際上會有一個相當(dāng)微妙的問題出現(xiàn)在大多數(shù)folk的實現(xiàn)上臭家,當(dāng)使用固定大小的線程池作為ExecutorService時方淤, 是很容易出現(xiàn)死鎖的。
那我們可以修復(fù)這個folk實現(xiàn)使其能夠在固定大小的線程池中工作嗎携茂?我們來看看不同的實現(xiàn):

  def folk1[A](pa: => Par[A]): Par[A] = es => pa(es)

這無疑是避免的死鎖,唯一的問題是带膜,我們實際上并沒有派生一個單獨的邏輯線程來對pa進行求值鸳谜。不過這仍然是一個有用的組合子钱慢,因為它讓我們做到延時計算的實例卿堂。讓我們來給它一個更加適合的名字懒棉,delay:

  def delay[A](pa: => Par[A]): Par[A] = es => pa(es)

但是我們很像能夠在固定大小的線程池中運行任意的計算。為了做到這一點穗慕,我們需要為Par挑選另一個表示類型妻导。
用Actor來實現(xiàn)一個完全無阻塞的Par
怎樣才可以實現(xiàn)一個非阻塞的Par表示類型呢?我們可以嘗試自己寫一個Future類型替換java.until.concurrent.Future倔韭。

  sealed trait Future[A] {
    private[chp7] def apply(f: A => Unit): Unit
  }

  type Par[+A] = ExecutorService => Future[A]

基于新的Par類型,讓我們重新實現(xiàn)API:

  sealed trait Future[A] {
    private[chp7] def apply(f: A => Unit): Unit
  }

  type Par[+A] = ExecutorService => Future[A]


  //接受一個已求值的A胰苏,返回結(jié)果將會在另一個線程中執(zhí)行
  def unit[A](a: A): Par[A] = es => new Future[A] {
    def apply(f: (A) => Unit): Unit = f(a)
  }

  //接受一個未求值的A醇疼,返回結(jié)果將會在另一個線程中執(zhí)行
  def lazyUnit[A](a: => A): Par[A] = folk(unit(a))

  //從并行計算中抽取結(jié)果
  def run[A](es: ExecutorService)(pa: Par[A]): A = {
    val ref = new AtomicReference[A]
    val latch = new CountDownLatch(1)
    pa(es) {a => ref.set(a); latch.countDown()}
    latch.await()
    ref.get()
  }

  //將par[A]分配另一個獨立的線程中去運行
  def folk[A](pa: => Par[A]): Par[A] = es => new Future[A] {
    def apply(f: (A) => Unit): Unit = eval(es)(pa(es)(f))
  }

  def eval(es: ExecutorService)(f: => Unit): Unit =
    es.submit(new Callable[Unit] {
      override def call(): Unit = f
    })

  def map2[A, B, C](pa: Par[A], pb: Par[B])(f: (A, B) => C): Par[C] =
    es => new Future[C] {
      def apply(cb: (C) => Unit): Unit = {
        var ar: Option[A] = None
        var br: Option[B] = None
        val combiner = Actor[Either[A, B]](es) {
          case Left(a) => br match {
            case None => ar = Some(a)
            case Some(b) => eval(es)(cb(f(a, b)))
          }
          case Right(b) => ar match {
            case None => br = Some(b)
            case Some(a) => eval(es)(cb(f(a, b)))
          }
        }
        pa(es)(a => combiner ! Left(a))
        pb(es)(b => combiner ! Right(b))
      }
    }

完善組合子為更加通用的形式
練習(xí) 7.11
實現(xiàn)choiceN秧荆,根據(jù)一個結(jié)果多多個計算進行選擇。

  def choiceN[A](n: Par[Int])(choice: List[Par[A]]): Par[A] =
    es => {
      val i = n(es).get()
      choice(i)(es)
    }

練習(xí) 7.13
實現(xiàn)一個更加通用的chooser

  def chooser[A, B](pa: Par[A])(choices: A => Par[B]): Par[B] =
    es => {
      val a = pa(es).get()
      choices(a)(es)
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陕赃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凯正,更是在濱河造成了極大的恐慌,老刑警劉巖廊散,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件允睹,死亡現(xiàn)場離奇詭異,居然都是意外死亡缭受,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門韭畸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔓搞,“玉大人,你說我怎么就攤上這事喂分。” “怎么了甘萧?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵梆掸,是天一觀的道長。 經(jīng)常有香客問我酸钦,道長,這世上最難降的妖魔是什么钝鸽? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任拔恰,我火速辦了婚禮,結(jié)果婚禮上颜懊,老公的妹妹穿的比我還像新娘风皿。我一直安慰自己匠璧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布魔眨。 她就那樣靜靜地躺著酿雪,像睡著了一般遏暴。 火紅的嫁衣襯著肌膚如雪指黎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天杂彭,我揣著相機與錄音吓揪,去河邊找鬼。 笑死磺芭,一個胖子當(dāng)著我的面吹牛醉箕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播讥裤,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼己英,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了损肛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤摩泪,失蹤者是張志新(化名)和其女友劉穎劫谅,沒想到半個月后见坑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡不皆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年霹娄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片项棠。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡挎峦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坦胶,到底是詐尸還是另有隱情,我是刑警寧澤峭咒,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布纪岁,位于F島的核電站,受9級特大地震影響幔翰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遗增,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一做修、第九天 我趴在偏房一處隱蔽的房頂上張望霍狰。 院中可真熱鬧饰及,春花似錦、人聲如沸燎含。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谚咬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間择卦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工祈噪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尚辑,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓月褥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宁赤。 傳聞我的和親對象是個殘疾皇子栓票,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容