博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js-csp 可以开始尝试了
阅读量:5809 次
发布时间:2019-06-18

本文共 3402 字,大约阅读时间需要 11 分钟。

CSP 的用例

CSP 的用法最早是 Go 语言传开来的, 看一下我从网上扒的代码:

package mainimport "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" 应该就能找到.

除了 Go, Clojure 也实现了对于 CSP 的支持, 也就是 core.async 这个库,

在 Clojure 当中语法做了调整, 成了 >! <! 这样的写法, 有点怪,
但是基本功能差不多, >!<! 都是模仿的阻塞, channel 概念也一样:

(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" 可以找到.

为什么用 CSP

看 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 的, 估计不能用, 但是供参考:

我直接贴一遍 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.jsping 1pong 2ping 3pong 4ping 5pong 6ping 7pong 8ping 9pong 10ping: table's gonepong: table's gone

这样模拟的就是两个进程之间相互发送数据的场景.

但实际上 CSP 可以对事件流进行抽象, 也就能做出更强大的功能.

这就是在我之前推荐的这篇文章上的做的介绍, 点进去看吧:

随着浏览器和 Node 对 yield 支持的完善, 使用 js-csp 已经可以做到.

考虑到方案的灵活性, 我认为值得往深了去挖一挖.

和 Rx 的对比

事件流的另一套有名的方案就是 Rx, 有 js 版本的 Rxjs.

大概来说, Rx 是用 OOP 语法封装的 FP 风格的响应式编程方案, 操作繁多,
而 CSP 通过管道提供的是一些灵活但过于基础的原语,
看社区的讨论, 其实有很大的重叠的部分, 尽管细节还很难说...
我搜集了一些文章:

还有 GitHub 上的一些讨论:

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

小结

说起来我还没怎么消化这东西.. 但是如果看过文章里的 Demo, 你一定印象深刻,

流是数据和时间绑定在一起形成的产物, 普通的编程手法很难处理,
但是 CSP 的概念让处理 Channel 中传递的数据成为了而比较灵活的事情.
参考国外社区的评论, 这是具备相当大价值的一块知识, 所以在持续跟进.

转载地址:http://chjbx.baihongyu.com/

你可能感兴趣的文章
Event事件的兼容性(转)
查看>>
12.22 repeater 添加
查看>>
我的2014-相对奢侈的生活
查看>>
zoj 2412 dfs 求连通分量的个数
查看>>
【转】inittab文件
查看>>
[ThinkPHP]打开页面追踪调试
查看>>
Java设计模式
查看>>
Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)
查看>>
001_vagrant利器
查看>>
用Swagger生成接口文档
查看>>
sublime快捷键
查看>>
一文读懂 AOP | 你想要的最全面 AOP 方法探讨
查看>>
Spring中XML,注解,JavaConfig如何选择
查看>>
搭建JEESZ分布式架构1--CentOs下安装jdk7(环境准备)
查看>>
数据更新| Qtum 量子链全球大使招募计划
查看>>
分布式锁的解决方案(二)
查看>>
如何写出一个好的单例模式
查看>>
类的设计-使可变性最小
查看>>
三、Android性能优化之常见的内存泄漏分析
查看>>
决战性能之巅 - Taro H5 转换与优化升级
查看>>