js-csp 能夠開始嘗試了

CSP 的用例

CSP 的用法最先是 Go 語言傳開來的, 看一下我從網上扒的代碼:html

package main

import "fmt"

func ping(pings chan<- string, msg string) {
    pings <- msg
}

func pong(pings <-chan string, pongs chan<- string) {
    msg := <-pings
    pongs <- msg
}

func main() {
    pings := make(chan string, 1)
    pongs := make(chan string, 1)
    ping(pings, "passed message")
    pong(pings, pongs)
    fmt.Println(<-pongs)
}

其中 <- 符號是往 channel 當中寫入數據的操做.
同時注意通常 <- 的位置對於 goroutine 來講是阻塞的,
因爲 channel 可以處理異步操做, 也就是說能作到異步代碼用同步寫法.
更多的細節搜索 "go channel" 應該就能找到.node

除了 Go, Clojure 也實現了對於 CSP 的支持, 也就是 core.async 這個庫,
在 Clojure 當中語法作了調整, 成了 >! <! 這樣的寫法, 有點怪,
可是基本功能差很少, >!<! 都是模仿的阻塞, channel 概念也同樣:git

(let [c1 (chan)
      c2 (chan)]
  (go (while true
        (let [[v ch] (alts! [c1 c2])]
          (println "Read" v "from" ch))))
  (go (>! c1 "hi"))
  (go (>! c2 "there")))

這個例子當中 (chan) 生成 channel, 而後用 go 生成 3 個線索...
雖然用了 while true, 可是經過 alts! 也造成了阻塞.
更新細節搜索 "core.async" 能夠找到.github

爲何用 CSP

看 Wiki https://en.wikipedia.org/wiki...編程

In computer science, communicating sequential processes (CSP) is a formal language for describing patterns of interaction in concurrent systems.[1] It is a member of the family of mathematical theories of concurrency known as process algebras, or process calculi, based on message passing via channels. CSP was highly influential in the design of the occam programming language,1 and also influenced the design of programming languages such as Limbo[3] and Go.[4]瀏覽器

CSP 原本是用於描述併發的系統之間如何交互的, 也就是在 Go 當中的用法.
因爲併發的操做一般都是異步的, 因此 CSP 也能適合異步的行爲.
最主要的概念就是 Channel, 也叫作"管道", Channel 能夠用於傳輸數據,
於是就有對於管道讀和寫的操做, 分別是 take!put!, Clojure 裏的叫法.
前面說了, 管道看上去是阻塞代碼執行的, 也就是說讀和寫能夠進行等待.
這樣就能模擬一些場景, 好比抓取網絡數據再打印, 就很容易寫出來了.網絡

常見功能還有 alts!, 對應 Go 的 select, 就是多個 Channel 取首先返回的數據,
還有 merge 記不大清, 好像是彙總多個 Channel 返回的數據, 變成一個?
其餘的 filter, map 等等序列的操做, 在 Channel 上也有相似實行,
另外一方面 CSP 在實用當中應該是進行了擴展, 實際功能不止這些.
好比說增長了 (timeout 1000) 這樣的 Channel 等待一秒返回數據,
還有對 Channel 進行 Buffer 的功能, 以及異步的推數據等等.併發

聽起來很花哨, 可是若是有動畫能夠展現一下就很清楚了, 我還沒找到...
從總體的思路上說, 這是對於異步事件的一種抽象, 能夠用來實現不少業務.
想一想辦法再解釋細節吧, 我這裏先介紹 JavaScript 這邊的狀況...異步

js-csp 的現狀

因爲 Node 6 開始有 yield, 用同步代碼寫異步成爲了可能,
因而有就有了 js-csp 這個模塊, 經過 yield 實現了 CSP 的功能,
我還看到一個用了 async 的, 估計不能用, 可是供參考:async

https://github.com/ubolonton/...
https://github.com/dvlsg/asyn...

我直接貼一遍 README 當中的例子, 本身看看能不能看懂:

function* player(name, table) {
  while (true) {
    var ball = yield csp.take(table); // 等待取得數據
    if (ball === csp.CLOSED) { // 關閉狀態特殊處理
      console.log(name + ": table's gone");
      return;
    }
    ball.hits += 1;
    console.log(name + " " + ball.hits);
    yield csp.timeout(100); // 等待延時結束
    yield csp.put(table, ball); // 推數據並等待對方取
  }
}

csp.go(function* () {
  var table = csp.chan(); // 建立 Channel

  csp.go(player, ["ping", table]); // 至關於啓動 goroutine
  csp.go(player, ["pong", table]); // 至關於啓動 goroutine

  yield csp.put(table, {hits: 0}); // 推數據等待對方取
  yield csp.timeout(1000); // 等待延時結束
  table.close();
});

運行的效果是:

=>> node go.js
ping 1
pong 2
ping 3
pong 4
ping 5
pong 6
ping 7
pong 8
ping 9
pong 10
ping: table's gone
pong: table's gone

這樣模擬的就是兩個進程之間相互發送數據的場景.

但實際上 CSP 能夠對事件流進行抽象, 也就能作出更強大的功能.
這就是在我以前推薦的這篇文章上的作的介紹, 點進去看吧:
http://jlongster.com/Taming-t...

隨着瀏覽器和 Node 對 yield 支持的完善, 使用 js-csp 已經能夠作到.
考慮到方案的靈活性, 我認爲值得往深了去挖一挖.

和 Rx 的對比

事件流的另外一套有名的方案就是 Rx, 有 js 版本的 Rxjs.
大概來講, Rx 是用 OOP 語法封裝的 FP 風格的響應式編程方案, 操做繁多,
而 CSP 經過管道提供的是一些靈活但過於基礎的原語,
看社區的討論, 其實有很大的重疊的部分, 儘管細節還很難說...
我搜集了一些文章:

https://medium.com/@puppybits...

還有 GitHub 上的一些討論:

https://github.com/ubolonton/...
https://github.com/cyclejs/cy...

另外還有某人用 Rx 寫法模仿 CSP 方案的博客:

http://swannodette.github.io/...
http://swannodette.github.io/...
http://potetm.github.io/2014/...
http://potetm.github.io/2014/...

小結

提及來我還沒怎麼消化這東西.. 可是若是看過文章裏的 Demo, 你必定印象深入,流是數據和時間綁定在一塊兒造成的產物, 普通的編程手法很難處理,可是 CSP 的概念讓處理 Channel 中傳遞的數據成爲了而比較靈活的事情.參考國外社區的評論, 這是具有至關大價值的一塊知識, 因此在持續跟進.

相關文章
相關標籤/搜索