In Solitude We Are Least Alone

Everything will go mad


  • 首页

  • 关于

  • 简历

  • 分类

  • 归档

  • 标签

未命名

发表于 2019-11-10

世界上孤独而沉默的兽

一

王子在爱人的怀中渐渐老去,枯竭的瞳孔慢慢扩散开来。

##

未命名

发表于 2019-10-23

头疼欲裂的深秋与醒不来的梦

JavaScript的多线程方案

发表于 2018-07-20

背景

Javascript是单线程+事件循环+异步IO模型,这种模型带来的天生缺陷有:1. 无法利用多核CPU的优势 2. 阻塞UI响应 3. Timer不能做到足够精确。
同时,针对异步IO所带来的Callback Hell问题,催生了Promise、asyn/await、协程等解决方案。但是这些方案并没有解决多线程的问题。
以下是从现有的方案中挑选的几种比较有代表性的方案。

官方实现方案

  • Web Worker

实现进度

目前Firefox Chrome Safari Edge均已实现Web Worker。只有Firefox和Chrome实现了Shared Worker。

应用场景

This allows for long-running scripts that are not interrupted by scripts that respond to clicks or other user interactions, and allows long tasks to be executed without yielding to keep the page responsive.
W3官方所给出的场景是:1. 长时间执行,也即意味着worker是一个重量级的解决方案。 2. 不负责响应用户操作,worker是真正的线程,多线程操作UI是GUI编程中的大忌(对此存疑),而且从编译/解释器实现上来说,最简单的方案是起一个单独的线程,创建新的Isolate实例和新的事件循环。 3. 不阻塞页面,显然,这是催生所有多线程方案的直接背景。
给出的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.html
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
document.getElementById('result').textContent = event.data;
};
// worker.js
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// found a prime!
postMessage(n);
}

通信/共享

postMessage + onmessage本质上属于异步通信,设计理念接近于Golang或者Erlang中的消息复制优于资源共享哲学。个人认为,这种设计的优点是屏蔽了传统的多线程模型编程中的同步细节,postMessage这个API设计的足够简洁,提供了一个较为普遍场景下的并行方案,同时也兼顾了js的异步风格。但这同时也是缺陷:首先,简单的消息传递不适合大块数据的共享,worker和主线程之间不存在共享变量。我在工作中处理过视频帧的编解码,由Worker线程处理好的视频帧数据通过postMessage传递到主线程,然后渲染到canvas上,过程中这个开销是比较大的;其次,Web Worker没有提供足够的同步原语,比如Mutex,用户无法精确控制线程的执行(无法通过Browser Context去postMessage通知worker暂停和恢复,因为现有的方案无法实现最基本的sleep原语。)相比Golang,Golang中虽然也推荐消息传递进行goroutine间通信,但是Golang的消息机制本质上是基于共享内存的,此外,Golang中的消息机制也不能说是异步消息,Golang中提供了suspend/recover机制,因此更接近于协程的概念。(Erlang这门语言我不熟悉,就略过了)
区别于上文中的Worker,官方还定义了SharedWorker。SharedWorker和Worker的关系类似于进程间的Anonymous Pipe和Named Pipe。这个与主题相关性不大。

结论

Web Worker可以说解决了一部分并行计算的需求,但是在数据共享和精确控制线程生命周期方面存在缺陷。

  • Shared Memory and Atomics

实现进度

SharedArrayBufer已进入ES2017标准。目前各主流浏览器都实现或部分实现,但是均保持默认关闭该特性。(UC Browser倒是实现并开启了)
Atomics仍然处于草案阶段,目前Firefox和Chrome已经实现。

应用场景

SharedArrayBuffer提供了多个Agent(在浏览器中表现为BrowserContext或者WebWorker)之间的数据共享方案。
官方指出的应用场景是:

Support for threaded code in programs written in other languages that are translated to asm.js or plain JS or a combination of the two, notably C and C++ but also other, safe, languages.
Support for hand-written JS or JS+asm.js that makes use of multiprocessing facilities for select tasks, such as image processing, asset management, or game AI.
即:1. 为其它语言转译到JavaScript或WebAssembly提供语义上的支撑。2. 为并行处理重量级的运算(游戏AI)和IO场景(如媒体处理)提供支撑,这一点弥补了WebWorker的大块数据共享方面的缺陷。

Atomics提供了内存的原子操作,也提供了一般意义上的mutex(Atomics.isLockFree)、条件变量(Atomics.wait/Atomics.wake),除此之外也提供了CAS操作(Atomic.compareExchange)以实现lock-free风格的同步方案。可以说是基本补全了WebWorker的同步原语。

第三方方案

  • Napa.js
    Napa.js是微软出产的一个多线程方案,作为NodeJS扩展形式。其中提出的Zone,从概念上可以看作NodeJS中的goroutine:不可对指定特定的线程进行特殊操作,屏蔽了内部的调度细节。从实现上来看,Napa Zone中的工作线程是真正的物理线程,每个线程拥有属于自己的Isolate对象,也因此,Napa.js对Napa Zone中的线程做了限制,只能访问部分Node API,以避免这些工作线程对主线程的事件循环产生干扰。

  • NodeJS的cluster
    使用多进程代替多线程是一种比较常规的思路,但是相比于Erlang的轻量级进程,NodeJS的进程还是太重了。

通信/同步

Napa.js定义了两个API,broadcast和excecute用于主线程控制Napa Zone中的工作线程。broadcast用来对某个zone中的所有线程做统一的状态管理,excecute用于交付实际的计算任务。从这个角度来说还有点像PHP的Swoole框架:通过主线程进行事件监听,在zone中进行具体的业务逻辑的处理。
在数据通信方面,Napa.js中的线程之间可以通过transportAPI传递内置类型或者实现了Transpotable接口的聚合类型。但是transport这个API比较丑陋,变量的传递还要是通过mashall这个过程。
此外也提供了多个线程共享同一个store的方式以实现共享内存。不过文档并不推荐使用store,我猜是因为其内部使用了读写锁之类的机制实现原子操作。

Napa.js是一个比较新的项目,目前并没有见到有什么大规模的应用。

结论

除了以上几种方案,还有一些用于特定场景的伪多线程方案。结论而言,值得期待的是ES2017的普及,Web Worker + SharedArrayBuffer + Atomics足以用在通用场景下。

预谋已久的告别和人海中的溺毙

发表于 2018-06-06

回过神来,我才发现自己正身处人的汪洋。这里是哪里?

啊,是了,这里是石家庄。我在看朴树的演唱会。四处回荡着《那些花儿》的歌声,然而并不是出自朴树之口。遥远的看台上我能看到朴树在灯光里,一手放在耳旁,一手拿着麦克风,侧耳听着来自观众的合唱。

古老的歌谣并不能让我回忆起久远的什么。相反,脑中不断回放的是两天以来发生的事情。

那是漫长的、预谋已久的告别。

一

三万人的体育场,日愈加深的近视让我无法从远处看台上黑压压的人群中寻找到某人。不过我也并没有刻意要找到谁就是了。我知道阿木就坐在更远的舞台对面的看台上,我原本以为一天前我们已经告别。

我已经六年没有见到阿木,甚至已经忘了他的模样和声音。这并没什么大不了,我只要细细回想一会儿,就能记忆起他左耳上的那颗小小的突出的肉球。但那时候我的座位在他的右边,否则我一定会忍不住伸手去摸一摸。

阿木说他养了两只乌龟,买了一个大的鱼缸,每天早上都被坚硬的龟壳磕到鱼缸玻璃的声音吵醒,于是他就把鱼缸搬出了卧室。还说到在春天乌龟的壳会像年久老化的瓷砖一样一片一片剥落下来。我一直以为乌龟的壳会随着它的身体一块长大,还一度疑惑乌龟的壳到底是什么做的,难不成绿巨人的裤衩就是这种材质的。

那天晚上我吃了一大份心心念念了一年的烤冷面。并不是说石家庄的烤冷面有多地道,北京虽说也有这东西,但毕竟没有吃上几次的机会。

朴树唱到《生如夏花》:

“也不知在黑暗里究竟沉睡了多久,也不知要有多难才能睁开双眼。”

“多「难」”,我对阿木说。但我也不确定当时到底我是对的还是他是对的。

“多……暖?”,阿木说,“是我,我一直以为是「暖」”。

像是一颗石子投入了久久未见波澜的湖面。

啊,究竟要有多难才能睁开这双眼。

二

我还知道对面的看台上坐着一位热爱摇滚和民谣的姑娘,也正是她我才得以坐在这里听一场朴树的演唱会。

姑娘是我的大学同学。我至今叫不上大多数同班同学的名字,但这位我不能不记得。

我本来打算过些日子去找她聊聊天,北京的生活暗无天日,我需要偶尔放松一下心情。当然,我没有轻薄到只为了排遣寂寞才去找谁聊天。我也不是辩解什么,坦白说,我是为了纾解长久以来对这位姑娘抱着的一点歉疚。对,即便这时候,我也认为是「一点」这样的程度。

姑娘喜欢许巍,喜欢朴树,喜欢赵雷。兴许喜欢许巍赵雷要比朴树多一点。但终究我也算是姑娘的同好。这一点或许很重要——喜好相同最容易使人拉近距离。人的喜好林林总总,但喜好中国民谣的人,十有八九也读海子的诗和村上春树的小说。诚然我属于此列,但也只是浅尝辄止的程度。我不认为拥有这些属性有多么难得,也许对姑娘而言,会有遇到知音的错觉。

这不平等。我一向以为,人只有站在平等的立场才能做朋友。

姑娘有时会以向人写信的口吻写一些文字,「左君」、「左少年」——这般称呼我。文风像极了村上春树(或者说林少华先生也不为过)。姑娘说我是像《挪威的森林》里渡边君一样的人。可我没有直子和绿子,不热衷咖啡和跑步,也不会把《了不起的盖茨比》读三遍。我甚至没有赢过谁一把桌球。

你看,我身上没有任何值得你知道的事情。

不过,如果你要问起,我也可以搜肠刮肚给你讲一讲我去过的为数不多的地方,听到的平平无奇的故事。

三

两天前的夜里,我坐在一个公园的长椅上。背后含苞欲放的荷花,面前不甚清澈但是在黑暗里泛起粼光的湖水,以及不时传来的低沉的蛙鸣,陡然间把我拉回不知几年前的某个夜晚。在同样的季节,同样的荷花待放的湖边,阿欣走在我身旁。我们绕着人工湖走了一圈又一圈,从滑板少年,从声势浩大的广场舞大妈们中间小心翼翼躲过。

我不想说谎,此时此刻我并不想念她。然而我还是打算告诉她我正在这里。我打开手机,却是她先发来一张口香糖锡纸的照片,问我纸片上的字是不是我写下的。写在口香糖锡纸背面的反向的字,如果翻过来看金色的一面,应该还能隐约看出当初我们写下的究竟是什么:

我心中尚未崩坏的地方,是否还残留着你的模样。

当时我还没有怎么听过五月天,晚自习课上,阿欣悄悄递过来一张纸条,而我并不知道那句只是五月天的一首歌的名字。后面那句是我为了押韵拼凑而成的,现在看来,满满的羞耻感扑面而来。那之后我才开始听五月天,从最初的闽南口音的口水歌到《2012》。我没有觉得自己中二,何况那时我的确正值叛逆。

之后我还是忍不住跟她说,你反过来拍一张我看看。她说没用,在小盒子里放了太久字迹磨平了。

“吶,我在这个公园。”

“我搬家了,不在那个公园的附近了。不过离原来的地方不远,如果你想见一面,我可以。”

“下次吧,实在没有时间,马上要回北京了。”

我说过我没有说谎,是因为此时此刻,我正忙于精心编织着词句来欺骗此时此刻坐在我身边的人。

四

从体育场出来,许巍的贝斯电音和鼓点还在城市的周围游荡。

“直到大厦崩塌。”

我蓦然想起原来这里还是万能青年旅店的故乡。

我没有赶上回北京的高铁,凌晨只有终点站石家庄的火车。不过哪里都无所谓,我只需要一个藉由离开那里的落脚处。

哪怕溺亡在这片人海中。



总之时间漫长,预言也好,诅咒也好,不妨一一试着接受。

时间漫长,关于你的事情还只字未提。

时间漫长,但是到此为止。

You can(not) escape

发表于 2018-05-10

凌晨3点46入睡,梦接二连三地袭来。6:00,天光透过米黄色的窗帘,于是不得不醒来。

梦一

第一个梦,说是噩梦也不尽然,倒是颇有日系动画的设定风格
梦中,我应该已经死去,或者我应该从未活过。我原本就是死者,作为死者的代表,来到生者的世界体验作为生者的生活。我坦然得跟来自生者世界的朋友介绍自己的家,说起后院里的井附近埋着我的尸骨。
“惨白色的,湿漉漉的胫骨”。我说。“你能想象到吧,就像——哎我也不知道该怎么比喻。”
作为生者的朋友却一脸亲眼看到的表情,”嗯我知道我知道,就像被食人族扔进锅里熬汤,最后把骨头捞出来的一样”。

死者之镇。

作为唯一在生者世界的留学生,不时有人向我问起生者世界的种种趣闻。
“呀,那可真好呐。”他们几乎总是报以羡慕的感叹。

“但你终究还是死者。”

我终究还是死者,总有一天不得不从生者的世界返回。

梦二

第二个梦,回到了高三的复习班,却是遇到了大学里时常一起抽烟的舍友。我们聊起各自的公司,聊到过去我教过他的一段神奇的代码。上课铃响,我们丝毫不必顾忌。
并不见当年凶神恶煞般的老师,庆幸的是,我不过是以现实中现在的我的身份回到那个教室的。所以即便是再遇到那些老师,我也不再会故作礼貌得向他们问好了。
在这个并不怎么熟悉的学校里,我终于可以光明正大地向陌生人借一只火,唯一有些担心的是回家会被大人说道。
再正常不过的梦吧。
我原本应该对那个时代毫无留恋,却总是不经意被梦境裹挟着回去。那里的一砖一木都让我感到厌恶。所幸物是人非,现实中的我身在异乡,在这里我是生者,他们才是死者。

梦三

空洞。

梦四

大概是因为工作中常常跟一个测试妹子打交道的缘故,梦到一位长发披肩的温柔姑娘。
然而很不幸,我首先喜欢短发,其次是马尾,黑长直只能排到第三。

一切都有所隐喻,一切只是荒诞闹剧。而梦中我无暇深思。

射向虚无的子弹

发表于 2018-01-01

黑夜总是相同的黑夜,23岁的或者是24岁的,石家庄的或者是北京的。冬月十五的月亮,月光裹住十八层的楼,平庸的像一只拧在天窗上的照明灯。

送走朋友,放下窗帘,天光早早地暗下,困顿袭来。醒在下午五点一刻。 橙子安静地躺在桌上,键盘灯沉默地明了又灭。

候鸟不知所踪,更无从在天空划下掠痕。红绿灯路口,穿梭来往的车辆,灯光渐渐狰狞。记忆并不可靠,目中所见,仿佛上演了几十遍的连续剧。所谓Dejavu。

2017年,一颗子弹射向虚无的天空。

12…4
ZuoXinyu

ZuoXinyu

ZuoXinyu's personal web-log

20 日志
5 分类
8 标签
RSS
Github Twitter Weibo Zhihu
  • 秉烛夜游,良友以也
  • 我是姚土豆
© 2019 ZuoXinyu
由 Hexo 强力驱动
主题 - NexT.Mist