Warning: Undefined global variable $debug in /var/www/ourcoders/tiny4cocoa/application/controllers/baseController.php on line 124
有个梨UGlee 的技术动态 - OurCoders (我们程序员)

有个梨UGlee的技术动态

有个梨UGlee
2020-02-04 19:08:30 发布
让我们重新审视一下「漱口水」对防疫是否有作用。

在SARS的研究中,研究者发现,患者的唾液中含有很高的病毒载量,网页链接 ,而且研究发现,对于一些患者,在发病之前就可以在唾液中检出高病毒载量。

目前普遍的认为SARS病毒是在下呼吸道复制为主,在上呼吸道未出现症状之前,理论上它 ...全文
有个梨UGlee
2020-01-23 11:07:56 发布
网页链接

传染病学电子书,大家可以春节期间在家研读,不出门。
有个梨UGlee
2020-01-21 00:00:00 发布
想想那些写内核的人,精心设计的数据结构殚精竭虑追求的效率,节省下来的CPU cycles,顷刻之间就被我等写JavaScript,Python,PHP的开发者浪费殆尽,哈哈哈哈,想想就开心,写脚本语言的都是富人哦!随意挥霍系统性能!
有个梨UGlee
2020-01-20 23:08:00 发布
王大锤:口罩没有了,也买不到了!
牙医姐姐:卧室柜子抽屉里有多余的乳罩,你可以先对付一下。
有个梨UGlee
2020-01-20 00:00:00 发布
Folk的File Structures这本书找对了。花了600页的篇幅其实主要就是讲B-Tree和B+ Tree。这个在今天看起来(会了就)很简单的东西,在1963年的AVL Tree诞生之后,学术界和产业花了十多年的时间才找到,有些匪夷所思。

基于B-Tree和B+ Tree的磁盘文件数据结构是存储大数据集最简单和高效的办法;如果用Append Only的模式,还很容易对付系统掉电故障;现代嵌入式硬件使用的flash存储介质(emmc or ssd),iops非常高,而异步编程框架也非常成熟,这意味着良好分开的数据集设计,分成多个文件存储,其读写性能可以显著好过SQLITE这种只能排队很低并发的嵌入式数据库。

这本书推荐给做嵌入式系统的朋友,在你的瑞士军刀库里增加一把利器。
有个梨UGlee
2020-01-19 12:08:50 发布
“去美术学校当老师,不就是图个免费性生活,”王大锤said,“不然还不如做个Python程序员。”
有个梨UGlee
2020-01-17 00:00:00 发布
The thread which I want to pick up is the semantic basis of concurrent computation. ---- Robin Milner "Elements of Interaction".
有个梨UGlee
2020-01-16 18:12:20 发布
说一下Dart。

Dart和Node几乎是一样的运行模型,全异步io加事件驱动;但是Dart有三个显著的优势,第一,它有类型,第二,它是编译执行的,第三,它使用isolate支持多线程。

在Node里如果要支持多线程以应对密集计算,需要启动一个新的vm,有显著的内存开销,在这个问题上Dart完胜。

Dart的类型系统支持让它回到了class-based inheritance上,类似Java,而不是JavaScript;其实有点儿遗憾,prototype-based inheritance在语言模型上更纯粹,但是它有一点效率问题,Dart的“退步”可以看作一种工程上的取舍,也不会造成太严重的问题。

++++

在有isolate支持下,isolate之间的通讯只能是异步的;最基础的设计要求应该是可以在isolate之间建立stream,尤其是在一个线程里创建的stream可以pass到另一个stream里,相当于golang或者pi-calculus里的pass channel over channel,这是asynchronous pi里最重要的设计原语,应该在语言级有良好支持。

举个例子。

比如http server有formdata,或者更宽泛的说,在server端demux一个stream,这时最好的办法是能够创建一个sub-stream对象(source),把它交给另一个isolate/thread继续处理。

stream在异步编程里的重要性几乎和语言里的原始类型接近,也是node吃饭的家伙。它可以看作channel概念在事件模型下的实现。实际上大量的调度工作都可以抽象成stream,例如在node里有object stream的概念,其中的object可以是一个job request(可包含一个callback),统一的stream设计可以处理buffer, delay, debounce, batch等等异步通讯里的常见问题,在node里实现一个stream的设计非常出色。

++++

asynchronous vs synchronous是一个并发的本质问题。

这一对概念不仅仅在编程尺度上使用,在网络尺度,在操作系统的底层,CPU和总线设计等等地方均适用。

几年前在基于Petri Net模型设计并发组合时问过Lo姐(@红烧Lo)一个问题,基于synchronous组合的,当时Lo姐反问了一个问题就是为什么这个组合要求同步而不是异步?当时我回答不出来。

支持同步的证据是Inria大学的一些研究,可以在Google scholar上搜索Synchronous Method找到;另外类似方法在硬件设计上广泛使用,本质上它是IO状态机组合时的同步迁移,IO状态机是经典状态机的一个拓展,状态机组合不是靠状态空间相乘实现,而是靠同步IO强制在指定的状态共同迁移做到。这种迁移,实际上在缩减状态空间组合,而状态机具有可验证性,尤其是硬件的状态空间不大时。

++++

但是Synchronous的迁移在应对设计变化时非常不灵活。

常见的情况是,如果出现一个设计变更,一个数据源突然变成了需要异步读取才能获得的,这个时候同步状态机必须修改,有可能波及的范围很大;这是实际项目中很常见的情况,比如一个原来在内存里存储的数据,因为数量增加,被临时持久化到磁盘上,这个时候在内存中的读取如果似乎cache hit可以同步继续,但如果cache miss,必须等一次io,这是无法遇见的。

Synchronous迁移设计的一个好处也需要强调一下,就是对现代处理器而言,所有的同步迁移,在代码上都可能因为激进的inline和jit,获得显著的性能提升。这是Node的emitter, callback, 和stream的高性能的法宝之一。

Asynchronous则更加灵活,而且能更好的处理一些常见问题,例如buffer, debounce和batch等等,实际上这些都是面向通讯(io)编程的必要构件。

++++

但是当你问到正确性时。

我们举个例子,譬如file stream和socket stream都有一个flush方法,但是当很多stream pipe起来之后,这个flush是没有办法在底层很好实现的。

在这里"worse is better"哲学发挥效力的地方是,你不要试图构建完美底层,远端是否正确收到了全部数据应该考虑在上层协议上实现,例如对方应答一下收到的数据大小甚至checksum,然后close stream,而不是依赖一个flush的使命必达;在io里唯一需要使命必达的是顺序,而这一点,也是在tcp而不是ip层实现的。

所以设计上并非无法验证,而是设计假设变成“只要发送者的output是按照出发的顺序抵达接受者的input,那么这个程序是可以正确工作的”。而在设计上需要考虑的pitfall就是那些客观存在情况,顺序出发的操作请求被乱序执行。

例如你在node里同步发出两个文件操作,你并不清楚哪个会是最终结果,甚至他们互相之间有干扰。

设计上需要保证即使存在这种乱序执行,仍然可以得到想要的结果。这也是并发编程的本质。

++++

All in all,对于synchronous,理论上,如果编译器很聪明,它可能发现一个io是可以优化掉的,就像inline可以优化掉function call一样;但是asynchronous,它就困难了(但不是不可能)。在这个时候,数学变换能够适用,性能收益极大。

但是asynchronous,是在各个尺度上普适的,它很灵活,效率不是那么好,有一些pitfall,但仍然是可以保证正确性的,毕竟你可以等待一个应答再继续操作。
有个梨UGlee
2020-01-16 00:12:20 发布
今天竟然从fae窗口拿到了pin delay文档。。。简直奇迹。。。。
有个梨UGlee
2020-01-15 21:12:31 发布
stm32mp1发布快一年了。st给了一份极好的ddr routing guide。软件主要基于yocto,也有Debian支持但协处理器开发就不知道怎么搞了;也不清楚驱动mainline的进展如何。这货基本上是要在布板上难倒MCU工程师的,不知道st是不是会官方出SOM。
有个梨UGlee
2020-01-15 21:12:31 发布
arduino都用上type c了,2020真的来了。网页链接
有个梨UGlee
2020-01-13 00:00:00 发布
hierarchical resources。

++++

包括文件系统,xml文档,JSON对象,restful API,甚至document db等等,都是层级资源描述;层级资源描述非常常用,虽然不是万能的,比如我们需要更复杂的关系表述和查询时,可能需要诉诸真正的数据库。

但是很奇怪的是我们为什么要使用这么多种不同的方式。

文件系统的缺点是两个,第一它没法一次性读取一个subtree,比如Linux的proc/sysfs象注册表一样暴露了很多内核信息,但没法一下子读回来一个目录内的所有文件内容,也有可能在多次读取的过程中遇到内容变更,导致数据不一致。这是xml或者JSON这类文档结构的好处。

文件系统的第二个缺点是它是使用name value的,name相当于是一个identifier,一个目录内的文件不得出现相同的名字;这个设计粗看是OK的,但是有严重的隐患,就是这个identifier,是client提供的而不是server(kernel)提供的。你想一下就会发现这个设计和restful资源不同,restful资源的唯一ID是server端分配的。

实际上文件系统也有inode number可以作为唯一ID标识,但是这里有个很大的麻烦,Unix上文件的权限设计是基于path的,path包括hardlink和symbolic link,link可以表述一个引用关系,实际使用中相当灵活,能解决不少问题,以此来补足层级结构实际上是partition的问题。

Unix上的资源访问是沿着路径检查的,和link一样这个简单的设计也解决了很多实际问题,但是这个设计是Unix里唯一的(文件)资源访问时的基础权限设计,换言之,它没有基于inode number的资源访问方式,因为没有机制auth,而且由于link的存在,构建一个map来反向查找也不可能,一个资源可以有大量经过link的路径,其中一些可能是允许访问的,另一些则不可能。

所以这里拿restful对照的话就会发现,古老的Unix文件系统设计在把文件当作「共享」资源服务时有天生的弊端。

++++

xml和JSON用于解决另外一类问题,两者相比而言,xml更完备一些,它有更好的schema定义,节点有attribute;但JSON更加literal,象简洁的口语;document db很多的时候就像大量不规则xml或JSON资源的可查询版本。

++++

综合来说,我们发现在资源表述上存在这样一些问题。

这个层级是有刚性边界的,比如HTTP path其实也是hierarchy,只有不多的HTTP服务实现上允许更长的path访问到JSON对象的层级(即访问到内部去),这个刚性边界的存在其实并没有意义。

此其一。

其二,文件系统有相对路径的概念,多数操作系统都支持系统,甚至程序,有自己的namespace,例如Unix里著名的mount,挂载点的位置是程序自己定义的,程序可以根据需要构建自己的namespace,程序可以从一个path读取数据处理后保存到另一个path去。这个相当不错的特性,在xml/JSON流行的时代,竟然丢失了!换句话说,网络资源都只能基于绝对路径工作。如果操作系统设计成这样是要挨打的。

++++

这篇微博没有结论,只是抛出问题。

网络资源表述在允许大家瞎发明层级结构的资源表述,然后把简单的代码重写很多遍;就为了对付路径或者包含关系或者资源的namespace这么简单的问题。

Unix先驱们发明文件系统时的统一抽象和由此带来的代码精简和重用精神,都被丢弃了。
有个梨UGlee
2020-01-13 01:08:58 发布
今年嵌入式的看点仍然是st的双核A7。

arm也好,st/nxp等做cortex m的厂商也好,憋了很多年的rtos,最终发现开发者完全不买账,开发者就是要linux,有linux就意味着无与伦比的网络协议栈和设备驱动,完美的开发工具链,极高的开发效率。

所以可见的未来里,很多MCU厂商都会杀进低端cortex A市场,应该说全志和瑞芯几乎错失这个机会,本来他们有很多产品都在这个价位,如果对开源软硬件的投入再大一点,目前应该已经可以有一个壁垒了。但现在还没有。

Anyway,象st等MCU企业杀入这个市场有很多好处,首先能看到的就是简化的电源和系统设计,独立的cortex m用于低功耗应用,更好的电源管理和mainline内核支持。考虑到cortex m向cortex a的进化增加了ddr和emmc,显著增加了工程难度和成本,未来还看这些MCU企业如何应对这个问题,SIP是一种方式,但也可能出现更好的方式。
有个梨UGlee
2020-01-08 23:07:49 发布
德仪真是业界良心,costdown它的am57x时出了一个0.65mm BGA的版本,然后就有了一个详细的布线手册,给了设计文件;国内厂商出这个pitch的处理器可能都几百个型号了,从来没见过这样的文档。
有个梨UGlee
2020-01-07 21:07:59 发布
写了两天Dart,整体感觉这是一个很有心机的语言。

一方面它设计和使用上希望象JavaScript一样轻盈;但另一方面在细节,尤其是效率上,做得很到位,数据结构的接口设计权衡了很多利弊,平衡简洁和效率,避免程序员写出太低效和随意的代码。

我估计设计者是有野心的,就是想做一个核心特性尽可能少,不像Java那么重的设计;同时在基础库接口上做opinionated设计帮助程序员写出简单和高效的代码,而不是象Java那样在结构上设计的极为通用,带来繁冗的代码形式和完全靠库来解决问题。

因为设计者是这个领域三十年的老兵,公认的top gun,所以可能也没兴趣claim什么或者积极求战成名,最后都留给时间来回答吧,它到底会不会撼动Java。
有个梨UGlee
2020-01-07 17:07:59 发布
自动化的定理证明可以看作是一种自动化编程么?
有个梨UGlee
2020-01-07 17:07:59 发布
谷歌如果用Flutter重写一个Android Studio,就是对这个平台最有说服力的支持了。可以取消对除了Flutter之外的应用的支持。改名Flutter Studio。
有个梨UGlee
2020-01-07 01:08:10 发布
"A recession is when a neighbor loses his job, a depression is when you lose yours. And recovery starts when Jimmy Carter loses his."

Ronald Reagan
有个梨UGlee
2020-01-07 00:08:16 发布
dart和node有个基础的不同,虽然看起来很像。

dart,react,Flutter是(鼓励)异步处理事件的;而node的callback和emitter(event handler)是同步的;这是两种完全不同的设计哲学。

全异步对UI来说是合适的,对客户端来说也还可以,因为客户端对错误的容忍度较高,用户偶尔退出程序重新进入不是太大的问题,而代码简单的工程收益很大。

但是node的同步方式是急剧缩减状态空间且易于做状态机白盒测试或验证的(对jit编译也有很大帮助因为代码可以更大范围inline,这也是node性能不俗的重要原因);全异步的测试非常困难。

在dart:async的文档里明确说了stream的同步事件处理是不推荐的;同步事件处理本身应该说在设计上是更优的,但是在设计变更时,比如一个原本同步的过程变成异步的了,状态机需要较大范围修改;但是把同步事件处理在文档中描述成“容易犯错”的也是喷了,你那全异步的处理连正确的定义都特么困难,有什么资格嘲笑同步状态机的设计定义呢?简直是贼喊捉贼的逻辑。
有个梨UGlee
2020-01-07 00:08:16 发布
js基本上就是一个很严重的功夫在诗外的语言,语言的基础构件很少,但要开发一个实际的应用要掌握的外部知识很多;

Flutter在这个问题上走的更远,需要做很多层面的知识准备才能开始写代码,不过好消息是它的基础库和工具链太全面了,一旦能开始写就有很高的产能,在UI代码上几乎是最高逻辑密度的了,写不多的代码就能实现很多的功能。
有个梨UGlee
2020-01-07 00:08:16 发布
Flutter最终提供了一个stream controller用于实现接近emitter的要求,但只有三个固定事件,data,error和complete(done)。

这种非要把应该在语义层面实现的东西塞进语法的人是怎么混进谷歌写基础库的?
有个梨UGlee
2020-01-06 23:08:20 发布
Dart的Async函数,可以用then/catch resolve;
Dart的Stream,可以用onDate/onError/onComplete listener;所以目测看起来似乎是和node的callback/emitter没区别的。

但实际上区别是巨大的;当多个emitter要组合时,互斥“拔掉”对方的handler或者destroy是极为常见的;这特么在Flutter里只能用闭包变量block了;在层级多的时候很麻烦;此其一;

其二,Dart的Stream竟然会区分Single Subscription和Broadcast,你大爷的,Event去耦的本质时去除message和message handler的耦合,你管它有多少个listener呢?我挂一个listener只为了debug行不行啊?

emitter只需要一个语义即可完成的事情,Dart:Async重新“发明”了一大堆函数解决。简直了。
有个梨UGlee
2020-01-06 23:08:20 发布
前端的很多state management都是弱智青年搞出来的;把不明真相的青年一代搞得更加弱智了。

开发者需要的是基于process的algebra,不是基于state的algebra;想不明白这个问题的人就不要整天发明框架了。
有个梨UGlee
2020-01-06 17:07:43 发布
flutter项目稍微正式一点就需要一个古老的前端问题,state management;有很多选择,不过我简单比较了一下就决定站scoped_model;这是一个粒度问题,scoped_model支持在一个build里访问不同的model,这个虽然有时会略繁琐但是可以scale,redux在web上也scale不了,到了flutter里一样fxxk egg。

++++

而且这个愚蠢的问题就是20年前的UI的hierarchical handler;ui的20年进化就是把原来10行代码做的事情搞成1000行代码来完成,只为了控件能飘来飘去。

飘来飘去~飘来飘去~妹有尽头~
飘来飘去~飘来飘去~妹有尽头~
有个梨UGlee
2020-01-04 03:06:57 发布
问个问题,四周飞行器为什么不加上一点水平翼,用于有风时利用倾斜姿态获得一点升力呢?
有个梨UGlee
2020-01-03 16:07:41 发布
Dart顶着Lars Bak和Kasper Lund的光环;但我感觉可能是上当了;这两位可能只有语言特性的否决权,语法是由一个JavaScript程序员组成的委员会提出来的;代码的观感非常childish;only teenagers love it.

++++

具体地说代码看起来很不严肃,缺乏抽象感,隆重的结构感,和精密巧妙的关系感;更像是CAD软件里零零碎碎的自动化脚本。

++++

当然这门语言的编译特性是无与伦比的,体现了前面说的那两位的盖世英明。
有个梨UGlee
2020-01-03 03:07:52 发布
小米不去fund一下Lars Bak那样的人和项目,就靠几个微博大V走不远的。
有个梨UGlee
2020-01-03 01:07:54 发布
无论是基于thread编程还是基于event编程,runtime都在极力掩饰调度这个问题,或者说把调度的责任扔给了runtime,开发者使用即可。

那么,假如说这件事情让开发者自己做,对应的原语应该是什么样的呢?
有个梨UGlee
2020-01-03 00:07:58 发布
dart里连变量都能await,因为变量是async getter实现的;flutter里防止race的主要办法是在UI上阻止用户,也是醉了,那写server呢?
有个梨UGlee
2020-01-02 19:07:58 发布
JavaScript一问:如果class constructor必须使用new,那new这个关键字是不是可以删掉呢?Dart是这样做的。
有个梨UGlee
2020-01-02 02:07:21 发布
真的是喷了!招商银行app的下载页面,这是下呢还是下呢?
有个梨UGlee
2020-01-01 22:07:25 发布
mmu是一个硬件层,不仅仅是kernel用,很多外设也接受,例如dma,(实际上内存控制器也是个硬件外设,在soc上),换句话说写驱动时,外设也可能接受这个地址,包括dma,isp图像处理器以及某些图形硬件加速,编解码器,加密硬件等;如果硬件不接受这一层那软件上的麻烦有一些而且地址要到处由软件翻译效率严重受损。另外GPU有自己的mmu也很常见。

kmalloc最贴近这一层。

vmalloc是利用mmu,以及mmu异常中断虚拟出的地址空间,不谈效率,它对软件使用内存是透明的,是软件意义上的内存。但很多硬件无法这样工作。换句话说这种内存纯粹是用于计算的地址空间。

memory本质上是IO,在硬件上体现的非常明显,说他是IO的意思,不仅大量外设IO真的被映射成了地址空间,还体现在它对硬件来说都是named channel,实际工作时的读写全都是基于总线通讯的,arm上包括内存也是通过和内存控制器通讯读写的,内存控制器甚至包含调度器让一些内存读写的优先级比另外一些高,以保证低延迟和实时性。

但是对纯计算来说,这些都看不到,所以纯计算使用的内存是另一层的,就像一个address space,容量仅仅受到寻址能力限制(如果系统可以swap的话)。

@字节跳不动
有个梨UGlee
2020-01-01 00:07:07 发布
Robin Milner有两个表述震撼到我。

一个是在他的图灵奖lecture里说的一个变量,可以看作一个process,读写都是process之间的通讯;这个模型一下子泛化了并发计算,也是让歧视性的所谓side effect一词,具有了客观和中立的表述;

另一个是他在他的学生的书的序言里说的,很多关于计算的idea,都是在计算机出现之前就有的;这看起来有点奇怪,但是也正说明了计算的本质,其实是在manipulating idea,而不仅仅是计算机做的那点儿事儿。

++++

大家,无论在那个领域,都具有哲学思维。
有个梨UGlee
2019-12-31 16:07:14 发布
年底了给大家推荐一本Flutter的书;Practical Flutter;适合老程序员速读 @hollylee8102 @刘鑫Mars ;我最近两周都在看这本。

书中快速介绍了dart和flutter,然后给了三个非常practical的例子。共400页。很容易读。作者是编程、写书、和讲课的老手,总是能写出你心里正想问的事情。

++++

Flutter是2019年的明星产品,谷歌的Flutter Interact大会也有很多看点;它支持iOS, Android,在2019年正式支持了Mac OS,对web的支持在beta channel;对Windows和Linux的支持在technical preview阶段。

Flutter的异军突起不是偶然,实际上它是十几年前大家对web技术的企盼;但是这件事情到现在也没能发生;Dart曾经计划在浏览器内支持但是受到广泛反对作罢;所以Flutter索性连沙箱这层脸皮也撕掉了,直接在OS上构建应用;这个曲折的经历证明了一点:就是这个世界上永远也不会缺少自己做不好事情还不让别人做事的人。

++++

Dart出自Lars Bak和Kasper Lund之手,设计初衷是尽可能的象JavaScript但是解决效率问题,这个目标应该说是做到了;但是老实说我觉得Dart团队太急功近利了,它现在的语言状态对更广泛的系统应用和Server端开发会很成问题,主要体现在对async的滥用上;anyway,写写前端是很OK的。

++++

Flutter的组件模型则完整抄袭了React设计,相当于一拳打在Facebook脸上;但是在整个工具链的完整性,开发和执行效率上,Flutter体现了一家涉足基础软件技术的大型软件公司的风范;虽然它不会在很近的未来危急React/Vue等流行Web框架,但是它肯定可以阻击这些框架通过Electron一类的打包方法向桌面渗透。

android, iOS, web, windows, macos, linux, chrome, fuchsia,一套codebase支持所有这些平台?听起来too good to be true?是的,但是它正在发生。

应该是涉足客户端开发的程序员在未来几年必须掌握的技术了。
有个梨UGlee
2019-12-31 16:07:20 发布
@程序员邹欣 老师的书到了。
有个梨UGlee
2019-12-28 03:07:28 发布
整个行业都把async关键字给了sequential process composition;堪称文盲典范;这个关键字应该给那些被独立编译扔进线程池运行的函数。

async之所以流行是因为if等流程控制语句在这个设计下可以方便使用;但是!流程控制语句(来自algol60)很可能是现有语言中的最大bug,函数式编程里的pattern matching应该看作更好的面向未来的设计。
有个梨UGlee
2019-12-28 02:07:21 发布
本质上我们在程序里写的是process,是process calculus意义上的那个,如果不清楚这个概念把process理解成一个有态有行为的抽象对象即可。这包括函数和程序语言意义上的对象。

一个process在结束时,会给另一个process发送message,这是我们组合process构成复杂程序的基础手段。

对于最常见的一个函数调用了另一个函数,被调用的函数返回可以看作这个process结束,发送了一个message。

当然理想情况下是结果,但也有可能出现错误。抽象的逻辑是,用于继续的process有两个!一个是继续正确结果的,另一个是继续错误的,这两个process是二选一执行,换句话说是互斥的。在pi calculus里这两个progress的运算符是➕,叫summation。

这个符号几乎是写并发时最重要的进程运算符号,但是,特娘的,在所有流行编程语言里都妹有。

我拿node说个例子,比如emitter,用户最需要写出多个event handler的代码,只要其中一个fire,其它的自动被取消,这个当然能手写出来,但是巨烦琐。所以node里充斥着removeListener这样的代码。而概念上,他们只是表达了一个continuation的互斥关系。

++++

在计算机还没有跟IO打交到,程序是所谓的sequential process的年代,程序被看作是pure function;在出现IO以及其它现代系统的诸多并发特性后,这种函数形式被保留下来了。Unix和C的设计目标是「虚拟」一个看起来象sequential program的东西,即一个process,操作系统意义上的。

在这种设计下,两个互斥的handler,或者说process calculus意义上的process,被代码层面强行merge成了一个block或scope里的代码。这是噩梦的真正原因。否则只是一个error handler装在哪里(做谁的continuation)的问题。

++++

Benjamin Pierce搞了一个基于pi calculus的语言,但是它的处理方式更类似go的CSP;我的理解是,在语言层面这样理解channel是错的,太重了,现有语言的reference都是channel,我们需要的是一个continuation的互斥(包括条件互斥)的表达式而不是go的那种channel。

++++

在这样的语言出现之前,我能想到的可做的就是代码中没有形式体现,但是心中(设计上)分离error处理路径和result处理路径,代码层面巨繁琐且易错,互斥路径互相拔掉对方的handler。

my 2 cent @遊真·uZen
有个梨UGlee
2019-12-28 01:07:34 发布
说一下为什么我认为promise/async不能作为并发主力。

promise/async本质上一样。如果我们把系统的计算资源看作有限资源时,会发现promise/async是一个push machine,即有服务和计算请求时立刻开始执行;这个做法在可以水平扩展且以数据库作为共享资源(和持久化)的backend时,可行。

但是反过来说,你会发现这种随意分配计算资源的情况对于有限资源模型来说是不成立的。

想想操作系统内核,无论算力、io、还是网络带宽,都有fairness需求,不可能应为一个密集计算请求就把系统都hang住;当然在内核里做调度有一定的便利性,userspace任务都可以被抢先;但是这不意味着资源分配在userspace就不该做了,如果不做,系统的可用性会出问题;

同样的,在一些特定场景下,对priority可能会需要调整,一些情况下是某些任务天生比另外一些需要service,另外一些情况下,可能期望short job first以获得最低平均等待时间,无论那个,一个任务调度器都是不可少的。

++++

本质上这是流式处理的push模型还是pull模型,pull模型也可以称为是lazy的,任务都堆在队列里等着执行器来取;如果要保证有限资源下,系统的可用性或者部分可用性,最终一定会进化成这种设计,换句话说如果完全基于promise/async实现,当资源不足时,基本上需要全部重写才能获得这种调度能力保障可用性。

++++

在云计算上这个不是问题,但是对iot或者边缘计算,这是个大问题。
有个梨UGlee
2019-12-28 01:07:34 发布
最近写的一些代码里涉及通讯,DBus;在JavaScript里采用了一个偷懒的做法就是全部用一个object作为rpc的接口形式,在整个链路上传递,无论是method call, method return, error, signal,包括模块内部的和与dbus通讯的;从某种意义上说它类似command pattern,另外一种意义上说,它让程序用类似express.js处理http的方式组织结构。

我不确定这是不是一种面向通讯或者说异步程序的nature,但它确实让程序异常的compact;核心的部分可以说是tightly coupled;而JavaScript的无类型特性给这件事情带来方便,因为在一个message object的整个传递的链路上,添加和修改属性,以及调试都非常方便。

++++++

所以从某种意义上去问,Unix在一边(kernel)高举着一切皆io的设计哲学,而在另一边(userspace)实际上是在鼓励thread model而不是event model;它从很大意义上说,在unix诞生的时代,是在virtualize在unix出现之前的分时计算模型;但从设计哲学上说,这似乎是个基础的冲突,也很可能是今天在userspace编程时,“并发”一词被讨论得热火朝天的原因。
有个梨UGlee
2019-12-26 04:08:01 发布
跟flutter相比,node callback那点儿缩进算个P。
有个梨UGlee
2019-12-24 00:00:00 发布
过节送祝福还需要手工key,说明ai技术尚未普及,新浪还需努力!
有个梨UGlee
2019-12-23 02:06:54 发布
throw的语言实现,其实你选择写一次语言解释器就明白了。所谓try catch就是在主函数栈之外再建一个try catch finally的栈,引用主栈,这样在遇到throw的时候,知道栈回卷到哪里,即哪些function frame直接抛了。

c语言没有throw定义,但c语言里实现throw一点也不麻烦,实际上有很多c/c++的变种语言用预处理器做这个功能。

java是有栈定义的。throw也理所应当。

但go是个另类,goroutine相当于在userspace做了一套thread,本来在plan9里这个货是kernel提供的,alef可以在userspace直接用;但是在其它操作系统上,没有类似plan9定义的那种thread支持,go只能在runtime里全搞一遍。

go是鼓励细粒度的goroutine的,每个goroutine有一块在堆内存上分配的栈,这件事情让throw的实现变得麻烦,goroutine本身也不是类似fiber的coroutine,go的runtime有权把两个goroutine放在一个线程里跑,也可以放在不同线程里跑,如果有throw支持,channel如何处理也会很麻烦。

所以我的理解是即使go的错误处理看起来很像C,但本质两回事。

++++

同样的问题在unix设计里没逃掉。Ritchie说过为什么unix程序的stdout和stderr分开,最初的设计不是分开的,后来发现没法用。

在go里问题本质是一样的,是用一个channel,还是两个channel。不好平衡。
有个梨UGlee
2019-12-21 21:07:27 发布
当一个库项目基本完成代码和基础覆盖测试之后,应该考虑在这个项目里写一个有实际意义的demo,使用这个库。有实际意义的意思的可以实际使用而不仅仅是一个十几行的代码例子。

在写这个demo的过程里,你需要暂时忘记一下库的内部结构,尝试从两个角度来使用库。

第一,基于文档,例如对js来说就是jsdoc生成的文档,根据文档去使用API,发现文档不清晰的地方添加文档。

第二,考虑调试,例如js里有debug库,在实际写demo的时候考虑如何让调试这个demo更容易,底层或者内部可以如何打印得恰到好处,站在使用者的角度最关心那些事件、行为、和数据流。

这样在demo完成后,项目的文档和可调试性会被完善,期间也可能发生一些重构;到这部完成,项目才可以真正的alpha release。
有个梨UGlee
2019-12-20 00:00:00 发布
@刘鑫Mars 你上热搜了!
有个梨UGlee
2019-12-20 00:00:00 发布
red dot
有个梨UGlee
2019-12-16 13:07:56 发布
函数式编程(原图来自推
有个梨UGlee
2019-12-15 23:08:09 发布
怎么GitHub连个官方的app也妹有?
有个梨UGlee
2019-12-15 21:08:18 发布
根据npm的dispute resolution guideline写了封邮件给老外,让他把项目代码早已从GitHub上移除的包名让出来,四周以后有结果。
有个梨UGlee
2019-12-11 12:07:56 发布
问个问题。

有没有人试过npm install在npmjs.com上所有没有native code的包,估计装完了会有多大?10TB够不够?
有个梨UGlee
2019-12-11 04:08:03 发布
suppose网络里很多nodejs设备,都做了沙箱,即没有提供require功能但是在sandbox里在global上放了一堆常用函数。

我们从一个A节点开始,就像shell一样写一段node js程序,但是它可以显式指定一部分代码运行在网络中的哪个节点上,和require的做法类似,把source包成一个大函数然后to string即可发到另一个沙箱里执行。

这里统一抽象的方式有两个。

第一个抽象是类似RPC的做法,形式上可以是:

node[1].run(f, callback)

这个callback是本地执行的,f是远端执行的,callback获得的结果数据可以是从远程节点返回的JSON。本质上这个做法和云上的lambda很接近。它牛逼的地方是,在node这种纯异步的代码形式下你可以混写代码。

这就像在C里面写spawn,父进程和子进程代码是一套的,对开发来说非常方便。

第二个抽象是类似pipe的做法。pipe本质上,对node的设计来说,就是readable和writable。

那么代码形式上可以是创建一个readable在node A上,创建一个writable在node B上,然后就是node经典的pipe函数。但是背后是a和b直接走网络连接把数据pipe过去了。

这两个形式在node里都是和现有的异步和流代码很兼容的。包括emitter,也可以有remote emitter。

这个能力虽然不说是其它很多语言做不到,但是就算能做到,也完全不会象node这样纯异步加上js动态和可eval做起来简单。

这个才是真正的网络编程。现在的RPC种种,restful之流,都太玩具了。包括docker也一样是个补丁技术。

iot时代,nodejs想不红都难。
有个梨UGlee
2019-12-11 01:32:01 发布
为什么说dbus和systemd真香呢。

在嵌入式系统里用Debian时,系统服务依赖性越少越好。通过dbus可以直接对接resolved,networkd,timesyncd,wpa_supplicant,和bluez,使用node.js可以写一个很小的自包含的对系统网络和蓝牙管理的完整程序,比上蹿下跳的搞一堆脚本和命令好多了,尤其是网络变化时。

networkd是比networkmanager精简很多的设计,虽然功能有限但好在自包含和dbus的良好支持。对只有一两个网卡不搞什么微批恩的系统来说足够了。
有个梨UGlee
2019-12-10 22:07:01 发布
为什么还有从GitHub叛逃到gitlab的开发者?出于一种什么动机?反微软?
有个梨UGlee
2019-12-09 02:07:37 发布
在ls | grep运行在abc上的情况,实现上需要:

1 ABC上都有相同的沙箱,例如node。
2 C可以创建C和A,A和B,B和C的通讯连接。
3 C可以把程序注入到A和B上运行,可以使用创建的通讯和AB上的本地资源。

就像一个copy命令,扔给A的是readable,扔给B的是writable,两者pipe,把A上的一个资源复制到B去了。

在shell里运行这个命令也是spawn的,前面说的只是spawn到不同设备上去了。kernel提供的pipe,现在变成了在一组设备间自由建立连接。

unix pipe本来是blocking的,编程上说是构成了coroutine,π calculus里构成同步通讯。分布到不同设备上的话,就变成了异步的和buffered。

牛逼!!!!!
有个梨UGlee
2019-12-09 02:07:33 发布
卧槽我竟然想明白了这个问题。

假如有a设备,b设备,c设备,假设用户在和c设备交互。

在unix里的ls | grep xxx这样一个命令,其实是可以做到在设备a上执行ls,pipe到设备b上执行grep,然后结果送回c设备。
有个梨UGlee
2019-12-09 01:07:37 发布
Thompson的pipe api和McIlroy的grep是unix上最重要的设计。后者的cloud版本是map reduce。前面那个是什么呢?
有个梨UGlee
2019-12-08 16:07:49 发布
DBus设计者吹牛批说它的数据结构和编程语言兼容;实际上官方的Python例子也是继承的跟屎一样;在JS里如果要能做到和语言数据结构兼容,只能是一切皆Array。
有个梨UGlee
2019-12-08 14:07:55 发布
Chrome的全屏模式显示tab,显示tab number这种琐事也特么要装extension,和android刚出来的时候打开关闭wifi也要放个gadget在桌面上一样,这你大爷的有冒险意义!谷歌吃屎!我用Firefox去了。
有个梨UGlee
2019-12-07 00:00:00 发布
那些真正值得讲的代码,都是从一坨紧耦合的代码开始的;代码本身并没有功能问题,设计上加上一些文档和一些时间也是大部分程序员可以理解的。

但是当你真的要开始单元测试的时候发现很难做到unit,即使你知道mock,知道dependency injection,还是会遇到很多内部模块在单元测试时需要mock。

这时候出问题的地方就是reference。

我不知道在early binding语言里有什么好的办法,还是写一堆mock是正常的。但是在late binding语言里,解决方法是不要传进去reference,代之以它需要的最小的接口函数。这样单元测试就可以保持“单元”。

在js这样的语言里,结构性的reference可以在构造完成后再添加上去,尤其是双向的关系,这是更好的做法,因为它保证了双向关系的建立是在一处代码完成的。

一个对象可以逐步构造成full fledged,但是它可以有个最小的必要资源和状态,单元测试也是从这里开始,保证没有任何optional配置和附加责任的测试通过;然后是附加责任,一些附加责任可以设计成可选的,比如向对象传入一个emit函数就可以是可选的,有则emit,妹有则pass;至于外部关系的测试,不隶属于这个模块,而是属于容器。

如果你不能做到这样的单元测试,而是必须mock一堆依赖,或者必须把几个紧耦合模块组装之后才能写测试----这实际上已经是集成测试了----这说明设计出了问题。应该考虑结构和关系哪里出了问题。

一般而言,代码中出现一些所谓的helper class,需要握着外部大杂烩式容器的引用才能工作,就是有问题了。
有个梨UGlee
2019-12-07 23:08:48 发布
遇到不遵守restful规则的团队,还是尽早离职吧。

这不是说restful是铁律。但它是设计上的constraint,是syntax而不是semantic,是communication protocol而不是communication message。

合规的意义在于,你可以利用成熟的文档工具,lint工具,API自动测试生成器,可以利用广泛的库实现,可以在链路上 ...全文
有个梨UGlee
2019-12-04 14:07:42 发布
tdd的最大价值在于:

如果你发现测试写不下去,应该立刻停止写代码,开始写文档。

文档检查三类问题

1 接口是不是太隆重,太多行为语义,难以长命百岁
2 内部结构是不是太复杂,不够literal,太难以维护状态一致性
3 关系是不是太混乱,难构造,难销毁,数据流不简单清晰

把需要的使用方式一条一条列出来,包括功能如何提取和更新数据,包括各种constraint如何enforce,在哪里enforce,包括数据流路径上的每个组件是不是责任简单,只做source,sink,fan in,fan out或者filter一种角色。

通常的设计困难都发生在:
1 一些操作早期没考虑清楚,感觉上实现没问题,结果真正实现的时候发现爬reference爬的混乱
2 一些数据流上的节点承担了太多角色,既负责维护数据,又做了复杂的分发策略,尤其是要根据业务要求出现调用外部模块更新其状态

解决的方式就是
1 考虑数据路径增加模块封装责任
2 考虑使用事件和观察者模式规避对外部模块的调用,这是最重要的去耦合方式

把所有的业务要求都在脑子里dryrun一遍,确认接口,结构,关系三件事情都理顺了,再开始写代码或测试。tdd不是必须的工程路径,但是把问题问全了想透了是应该先做的。
有个梨UGlee
2019-12-03 19:07:57 发布
用JavaScript重写ffmpeg。。。
有个梨UGlee
2019-12-02 00:00:00 发布
testing是against spec的;spec里还有大量的non-functional的;对软件质量而言,粗粒度的接口测试,集成和系统测试,性能、压力和可靠性测试,用户测试,这些才是最重要的。

unit testing是against design的,是细粒度的设计要求测试,不是合规测试。说ut是可运行的spec是胡扯的。大家应该读一些正规的software testing and quality assurance的书看看,要深入了解IEEE830的software requirement specification是什么,feature list只是里面的一个索引而已。

不要被各种博客误导了,靠读博客是学不会软件工程和质量管理的。
有个梨UGlee
2019-12-02 00:00:00 发布
单元测试一般只能写很细的粒度,也经常白盒灰盒混着来,包括把内部方法拉出来测以避免构造太结构化的递归测试数据。

但基于spec的测试,需要做很多测试状态和测试数据的准备,基本上都是简单接口复杂环境和复杂数据的,跟单元完全相反;单元是刷墙式的盖接口,而接口这东西随着粒度越来越粗是越来越少和越来越通用的。
有个梨UGlee
2019-12-02 00:00:00 发布
大家对单元测试有很多误会。

单元测试和软件质量的关系,基本上没太大关系。单元测试的目的是应对软件变化,而不是保证质量。实际上有各种软件测试和工程管理的实际数据统计。找到bug的能力,单元测试最低。一种称之为explorative testing的技术,是最高的。常规的testing,也是很不错的。但unit testing叫做testing是个误会,它只是用了testing框架写代码而已。
有个梨UGlee
2019-12-02 00:00:00 发布
tdd最合适那些在依赖树的叶子上的机制模块,使用成熟设计,对接口稳定性和可拓展性都有足够的信心。前面花一点时间把这类周边清扫一下都测好,然后开始写那些有态的逻辑,quick and dirty,以最快速度实现外部接口,每种使用方式都跑一个例子,以此检查核心有态模块的状态、依赖性、数据流、构造、观察、销毁等等是否都fit,如果发现不fit查找设计原因。

如果前面的周边很多bug,这个quick and dirty根本quick不起来,会很伤神的调试底层错误;如果这个quick and dirty没有覆盖到足够多的使用场景和三百六十度的全方位检查,就可能出现吭哧吭哧的写了一大堆代码和测试最终发现有些用例下设计不合理只能推到重来,代价惨烈。

在写这种中等规模的集成模块时,写大量的在使用者角度的“假”代码很重要。假代码的意思是不去管实现和内部,站在使用者角度看,希望怎么样使用这个模块,如何构造,如何观察,如何销毁。

因为设计首选是关于接口的,其次是关于关系的,完全bottom up一层一层写上去很容易写出最终极其难用,关系复杂到谁也搞不明白,构造需要高超技巧,拆毁是闭上眼睛祈祷的集成模块。

所以好的开发方式是从两头squeeze出来的,bottom up写一点,top down写一点,最终双向的挤压会让你理解如何解耦关系,如何保证构造简单拆除方便,如何让依赖性和数据流向清晰明了。一般的问题里都会遇到一两个关键设计最终让结构相对简单容易实现容易使用容易测试。如果发现做不到。那不要急着写代码了,先把问题想清楚,如何解耦和分拆责任。
有个梨UGlee
2019-12-02 12:08:21 发布
曹丕走了七步,曹植写完了hello world。
有个梨UGlee
2019-12-01 14:08:33 发布
Android的很大一个问题是缺乏lts版本,他特娘的自己也知道用kernel的时候要选lts版本,但是不给开发者和用户这样一个选择。
有个梨UGlee
2019-12-01 03:08:24 发布
被万众推崇的Unix设计哲学,被Lisper轰得体无完肤。

请大家阅读Richard Gabriel的经典文章,Worse is better.

网页链接
有个梨UGlee
2019-11-30 00:00:00 发布
dbus有个ObjectManager接口可以一把抓一个子树的所有节点的接口类型和属性。它会emit interface added信号可以观察节点变化和节点的接口变化,此外还可以侦听所有的PropertiesChanged事件,这样等于是可以把一个子树的属性变化全侦听了。对于大多数系统服务来说还算方便易用。
有个梨UGlee
2019-11-30 00:00:00 发布
手机像素的一路狂奔,根本上解决了硬件体系的io性能问题,包括总线,内存,和持久化介质(ufs),为arm笔记本拿下市场做足了准备。
有个梨UGlee
2019-11-29 00:00:00 发布
文件系统在表述hierarchy的时候毫不费力,它也能象数据库那样表述foreign key,就是建一个link。但是文件系统在“抓一把”属性的时候很吃亏,比如一个文件夹里有很多用文件名和文件内容构成的键值对时,没有一个操作完成。

数据库实际上也是有hierarchy的,表是一层,记录是另一层,换句话说它是扁平的;数据库有能力在表内实现hierarchy但是查询效率很差;数据库主力用外键表述关系。

但有趣的地方是数据库的外键类似文件系统的symbolic link,如果被引用的记录删除,引用的记录也要做处理否则会破坏referential integrity,这和C语言的野指针类似。

但是对于有GC的语言,对象回收是根据引用的,例如Java,在文件系统上对应的则是不太常用的hardlink;这种设计下引用是对称的,并无法区分哪个引用算是主引用,就设计而言这应该是更好的,但SQL没采用这样的设计。

Document DB,Restful资源,都允许“抓一把”的方式获得一个子树;DBus的ObjectManager Interface也有这样的能力;这个能力主要收益是可以让一些数据被“zoom in”,就像一个JSON里原本被设计成primitive type的类型,后来演化成了集合类或者对象。它符合设计上的open close原则,操作语义不变但数据的结构发生改变。这一点是SQL的弱项。

但是hierarchy或者说是recursion,它天生是unbounded结构,在“抓一大把”或者想蹲在根节点上观察变化时有很大的麻烦,反倒是扁平化的SQL最适合观察,数据归类之后加filter也更有逻辑。

但Plan9坚持认为一切皆文件就是够了的。

++++++

问题:

假如在一个中等规模,譬如几千个节点的网络里,每个设备可以看到其它设备作为一个数据服务节点,你觉得那个抽象是最佳的呢?

1 一切皆文件,任何其它设备看起来都像文件系统可以mount到本地,顶层访问接口就是文件夹和文件,打开文件流再协商结构化的数据协议

2 类似rest,顶层是文件夹的多层结构,然后开始有集合和单例,单例是一个小号的document,操作原语是HTTP那几个,好像重用能力也是不错的;

3 所有节点在其它节点看起来都是一个大号JSON,可以封装成一个类似rx的读写访问,海量数据列表可以使用iterator和filter。

4 全部以SQL实现。这个肯定是灵活性最高的,但老实说最不可能广为流行,它需要的性能对很多弱设备来说不可行。SQL本身假定了强计算能力。

++++

一切皆文件还有一个很重要的好处是,如果一个可执行的项目自包含,例如bash脚本,它在mount到本地后可以直接使用,类似浏览器加载页面,且可以按需载入数据,还可以根据命名参数确定文件存取位置,包括存回远端,存在本地,存到另一个远端去,以及tee。这是unix最成功的地方,在云时代也没过时。
有个梨UGlee
2019-11-28 21:07:23 发布
在比较了unix file system, Plan9 9P, DBus API, HTTP Restful, SOAP/XML, 和SQL之后我们发现,凡是固化动词的协议设计都更为流行,即使在资源表述上收到限制;凡是开放动词允许程序员瞎定义操作原语的,最后都成了niche应用,唯一的例外是9P,但9P无法解决unix上已有的大量脏优化达到的性能要求,尤其是图形程序很困难。而它适用的分布式计算领域,时代还没到来。
有个梨UGlee
2019-11-28 20:07:24 发布
忙活了一下午就整完两个函数;快手代码和精细代码产能完全两回事啊。
有个梨UGlee
2019-11-28 17:07:27 发布
写代码一时爽,写注释两行泪。
有个梨UGlee
2019-11-28 16:07:24 发布
Reinventing Plan 9 .... Badly.

LWN上多人次使用了这个表述,荣誉都送给了lennart poettering。

DBUS里的一个最基础的Interface是Peer,只有一个Ping方法,可以获知对方是本机还是远程。但实际上可能只有打印机在用这个服务方式。DBus在很大程度上是希望达到9P的设计高度和OpenBinder或者Android Binder的能力。实际上一个都没做到。
有个梨UGlee
2019-11-27 00:00:00 发布
dbus有个type signature编码。

一般来说这种写parser是递归同时维护一个stack,函数入口是字符串的position,作为start点;

我写了个双递归,一个函数遇到opening token的时候先去查找到closing token,然后把内容截取出来,用另一个函数去解析出内容列表,两个函数互相调用,可以不用栈但是接口上要有start和end两个位置参数。

但是测试的时候后面这个有麻烦,而且遇到出错的时候难以给出良好的错误信息,没有stack不是很好理解。

明天还得老老实实写个基于stack的parser。唉。
有个梨UGlee
2019-11-27 00:00:00 发布
@算法时空 一般regular string parser怎么测试呢?
有个梨UGlee
2019-11-27 00:00:00 发布
跟大家分享一个Ubuntu的小技巧。Ubuntu的左侧启动栏的程序,可以用键盘的Windows键加数字键直接切换;比如在第一个的是Chromium,用Win + 1就可以启动后者切换;Terminal里,Alt + 数字可以切换tab。这样用vim开发的程序员基本上就能用左手按键切换所有需要的程序窗口了。

。。。耳边想起周杰伦新砖《左手很忙》
有个梨UGlee
2019-11-24 03:06:55 发布
把所有资源都描述成hierarchical JSON的好处是和文件相比,JSON是可以有schema的。

对于庞大的列表结构,可以使用iterator,iterator可以选择过滤器,排序,和sliding window size进行数据读取,相当于是针对readdir操作的增强。

和文件系统的inotify类似,JSON资源列表也可以watch,在列表发生变化的时候获得更新通知。

这个简单的设计,可以像unix的namespace一样普适。绝大多数客户端都可以用这样一个相同的资源抽象方式工作,而网络通讯协议的差异被隐藏在底层,应用开发者不需要关注。

和private namespace一样,对于一个应用,它构建的hierarchical JSON是可以自定义的,类似unix的mount。

++++

从这个意义上说,document db和文件系统的差异被抹平了。而象dynamo db那样的数据库可以看作是这种hierarchical JSON的内部实现,在接口角度看(data view),它就是一些array类型的数据支持几种不同的排序(indexing)。
有个梨UGlee
2019-11-23 22:07:00 发布
吃了一锅酸菜鱼之后我特么终于理解了,Plan 9和9P的设计是将来时,不是过去时;它唯一的设计问题是,需要对file做volatile假设,或者说file可观察,其它都是细节问题,包括支持metadata(类似HTTP header),支持middleware和negotiation,支持列表的排序,sliding window,过滤器等等,但这些都是detail。

伟大的是everything is a channel和private namespace,是集群运算的永恒设计。
有个梨UGlee
2019-11-23 20:07:00 发布
网上翻了半个下午的Plan 9。

除了官方的文档和Paper之外资料非常少,不过还是能找到一点;Youtube上有个10年前的视频简介;用户在一个完全灰色背景的窗口上点鼠标右键,在context menu里选择new,然后用鼠标画了一个矩形区域,之后这个矩形区域就变成了Terminal,出现了命令提示符。

在一个局域网内,如果有一些预定的Global name,比如source是另一个服务器;写下命令9fs source,就会在本地文件节点上mount目标服务器的namespace。

在Plan9里最核心的抽象,仍然是everything is a file;它走得更远一步,称之为everything really is a file,意思是在传统unix里的socket, pipe, device file, ioctl这些不象file,或者说象在file上打补丁,不是in-band传输(指read/write),而是side-band或者out-of-band(例如ioctl),都被统一了。

这个大一统的协议,叫做9P,是Plan9的最核心和唯一的接口抽象。Windows Server,鼠标键盘设备,文件服务器,都使用这个统一抽象;而且,在Plan 9上并不需要TTY(事实上也没有)。

----

9P在这样一些意义上类似HTTP,包括authentication,extension,都是in-band的传输的,例如HTTP的authentication是在header里的token或者等同的东西。

9P的实现不考虑client cache,这是和NFS或者CIFS的巨大差异,但是和HTTP非常类似,HTTP作为FS角度来实现的话,client cache也非常难做。

这个问题本身没有好的解法,例如两个客户端如果同时打开一个samba的文件,象二进制的Word格式文件,实际上是filesystem in file;如果client cache,存在一种情况是client vfs层向应用程序报告写入成功了,但是实际上这个修改无法commit因为服务器端的版本可能已经被另一个客户端修改了。

本质上这是一个资源粒度问题,HTTP server在设计上规避这个问题的办法是设计更细粒度的资源,这会污染客户端应用开发者的逻辑,它必须对数据持久层做一个可自发变动的假设而且必须应对细粒度的自发变化。

换句话说,9P在设计实现简单上,比传统nfs要更好和更加通用,但是性能不行;在细粒度化上,file system不能说不是对资源的好抽象,因为http也可以用hierarchy表述资源,但这样做的结果是违反了everything is a file的假设的,因为file就是一个原子化的资源,并没有sub file, sub sub file之类的办法细分;如果你把一个file拆成很多folder来做,那传统unix的各种stdio pipe就没那么通用了。

----

传统文件系统和HTTP RESTFUL还有一个非常重要的差异,就是资源标识是server分配还是client分配;创建一个文件要给文件名是client分配,这在RESTFUL角度看是不可理喻的,HTTP POST不是幂等操作,但是server保证标识唯一是解决冲突的特别好的办法。如果你做过文件系统同步功能就会知道这种client决定identity的文件系统设计,是fundamentally flawed,后患无穷。

----

9P仍然有在使用,最常见的一个例子是Windows的Linux子系统,使用9P把Host的文件系统映射到Linux中。为什么微软会选择9P,应该算是对它的设计简单,易于实现,以及广泛适用性的一个肯定吧。

----

Plan 9带来了很多好的设计思路,比如今天大家在BSD和Linux里看到的/proc文件系统。比如BSD的rfork和Linux的clone,比如Linux里因为容器流行而广为人知的private namespace (cgroups),当然最最重要的,是Plan 9带来的UTF8,让所有的操作系统和计算平台都受益了。

----

那么到底,everything really is a file的抽象,是过去还是未来呢?仍然是留给开发者们思考的话题。早期的操作系统开发者更喜欢grep, awk这样的工具,如果系统坚持everything really is a file的设计,这些工具都可以重用。

但是在开发的另一端,程序员们几乎无一例外的在书写自己的grep/awk,因为他们需要结构化的数据,数据关系的表述,所以网络服务使用xml或者json吐出数据,或者干脆是用SQL实现数据访问。

在这两者之间的设计还有一种,就是象USB协议栈或者蓝牙那样定义应用层的profile,这样A生产商生产的血糖仪可以被B服务商的应用读取,算是对互操作性(interoperatability)的一个回答。但迄今为止,在应用开发领域能够这样定义成标准profile的数据结构还是太少了,例如几乎每个web服务商都有自己的user account定义,这些都是业务导向的,投资人并不会在意在这里投入。

----

而科学家们没有考虑赚钱的问题,他们是在用科学思维考虑系统应该如何重用。

Plan 9就是这样一个科学家们设计的系统。
有个梨UGlee
2019-11-23 13:06:59 发布
做女人很酷!写JS更酷!(Python不行
有个梨UGlee
2019-11-23 02:07:20 发布
写代码什么是最重要的?

我记得Torvalds说过Linux并不需要天才工程师或者超级工程师来撰写,能做内核maintainer所需要的最重要的品质,是长期认真的维护一个组件,富有责任感,值得信赖,当人们需要他的时候,他就在那儿,无论是修补bug,还是添加feature,或者因为内核的其它组件API进化而跟着修改。 ...全文
有个梨UGlee
2019-11-22 20:07:25 发布
珍惜绳命,远离Python。
有个梨UGlee
2019-11-22 19:07:25 发布
关于HTTP Code有一个特别粗俗的解释是:400 -> Fuck you,500 -> I'am fucked。

但是返回错误代码的时候基本上就是这样的一个逻辑:

1 你丫不用retry了,结果都一样;(400)
2 你丫可以retry,高几率成功;(500)
3 你丫可以连续retry几次,如果都不行短时间内就不要搞了;(500)

除了1/2/3之外,就是某个环境依赖性完蛋了,你我都不晓得怎么搞了,定一个error code交给用户让他自己想办法吧。(但是能用1/2/3覆盖的case尽量用1/2/3覆盖
有个梨UGlee
2019-11-22 14:07:30 发布
网页链接 一篇在virtualbox里安装Plan 9的教程;但是不晓得是不是能在一个电脑上装一个集群看看Plan 9的威力。
有个梨UGlee
2019-11-22 13:07:30 发布
以下四样东西是强关联的,并且预示了未来:
1. Alan Kay的smalltalk
2. Bell Labs的Plan 9
3. Bill Joy力推的Jini
4. AWS的lambda/SAM,DynamoDB,和iot
有个梨UGlee
2019-11-22 09:59:34 发布
云计算
有个梨UGlee
2019-11-21 23:07:34 发布
和大家分享一个chrome浏览器彩蛋。手机的chrome支持多个网页显示成card,如下图所示,但是你有没有想过每张card的背面是什么样子的?你只要从下向上划五次就能看到了。
有个梨UGlee
2019-11-21 19:07:40 发布
第九计划简介 网页链接
有个梨UGlee
2019-11-20 21:07:41 发布
写了一个测试,抓出一箩筐bug。
有个梨UGlee
2019-11-20 18:07:44 发布
网页链接 RSA Signing is NOT RSA Decryption 投稿 @网路冷眼
有个梨UGlee
2019-11-19 00:00:00 发布
回答一下前面说的问题。

duplex stream的两个方向的结束,EOF,是除了destroy之外任何错误或者end结束之后都该抛出的,原则上和connect无关。connect和close并非成对关系。

为什么?

connect和close的成对关系是socket资源意义上的,就像文件描述符的open和close。但是stream的设计里,这个流是怎么来的,如何销毁回收资源,不在stream的通用接口设计考虑范围之内。

例如node的fs.createWriteStream,在创建stream之后就可以pipe数据进去,而不是要等到这个stream真的打开拿到文件描述符。

网络连接也是一样的,connect就相当于文件描述符拿到了。但是良好的设计不应该要求使用者自己去block,等到连接创建之后才开始发送数据。所以从这个意义上说,connect是side band消息,不是in band数据。

close只意味着一个真正的结束,在close之后不会再有任何事件发出。如果有什么东西要在这里继续,这是最好的一个代码位置。

node的stream都是为了pipe设计的。pipe本身相当于成功路径,不管错误情况。如果一切顺利,所有其他事件都可以忽略。如果出现错误,那就全部报废。所以使用和实现的原则是:

全路径都要保证end和finish必须emit,这样所有的stream都可以正确完成自己的资源维护,当然这不意味着全部数据流都是正确传输了,只要有error抛出,你就可以假定是全失败了。

这个设计哲学规避了考虑connecting和connected的状态差异以及由此带来的编程问题,尤其是各种等待和同步。

从这个设计可以看出node的设计哲学,是乐观主义的。全部搭好一个流组合,如果没问题,谢天谢地,如果有问题,再来一次,但坚决不去深入到细节研究corner case的状态组合。可以说是非常简单暴力和实用主义了。

但大道至简,正是node和js的聪明之处。
有个梨UGlee
2019-11-19 00:00:00 发布
问大家一个代码问题。

对于一个stream的实现,例如tcp socket,close事件是应该和connect事件成对呢?还是与connect无关?即使connect失败也要抛出?

read path和write path的结束事件呢?对于node来说分别是end和finish。

1 是否和connect有关?
2 在出现错误时呢?是否可以不抛出其中一个或者两个?

大家来发表一下看法。
有个梨UGlee
2019-11-19 00:00:00 发布
展示一下教科书级的代码 网页链接 (错误代码还没定义完成
有个梨UGlee
2019-11-16 15:06:45 发布
绝大多数node callback代码,也就是喜欢coroutine线程模型的开发者们说的continuation,是具有pi calculus意义上的summation组合关系的,但是代码层面很难简单表述,也很难检查完备性。
有个梨UGlee
2019-11-13 01:30:07 发布
也不知道用go和typescript的人哪儿来的自信,这俩和kotlin一样都没有前途。强势语言特性的一大特点就是被广泛抄袭。它会导致同一种语言实现有多种方式,以及同一类问题在多种语言内被解决,最终针对单一问题参与者众,进化的快。

如果你的工具不具备这个特征,那你就会花海量时间在收拾工具而不是使用工具上,纯属浪费绳命。
有个梨UGlee
2019-11-09 00:00:00 发布
网页链接 跟大家分享一本书。Implementing SSL/TLS。书本身对大多数开发者来说都每什么意思,因为几乎不会有机会写这种代码。但是有意思的部分是安全专家们找到了多少种办法攻击这个协议。有很多匪夷所思的办法。感觉就是网络支付其实很危险。
有个梨UGlee
2019-11-05 00:00:00 发布
dynamo db简单的说,就是你想看到query的结果长什么样,你就用这个格式把数据存进去;加上index,这个表越紧凑越好。这不可避免产生数据冗余,可以使用transaction API实现数据插入、更新和删除。

super fast query,super best scalability,基本上没有什么flexibility。管它叫数据库是个误会,它就是把内存里的data set分成hash table和sorted list的做法扔到云上去了。

那为什么在即使数据量不大的情况下也愿意选择dynamodb呢?最重要的原因是它的事件流可以让你的整个Serverless应用完全基于reactive模式工作,数据库是observable的,这是sql数据库很难做到的。

换句话说,Smalltalk的梦想在云上实现了,无限scaling的能力,加上lambda的blue/green热升级;你如何构筑一个可以hot patch的系统级应用,你也可以用同样的模式构筑一个云上的应用。这种编程模型意义上的scalability才是最具有价值的scalability,而不仅仅是一种维度的能力扩展。
有个梨UGlee
2019-11-03 00:00:00 发布
dynamo有个据说是开源版本的实现叫Voldemort,在GitHub上,网页链接,可供 @zhh-4096 批判。
有个梨UGlee
2019-11-02 00:00:00 发布
如何把图中这样一个关系型数据库的多张表,塞入NoSQL(DynamoDB)的一张表(以及为什么要塞入一张表),看这篇文章 网页链接

同样的问题在aws DynamoDB文档的Best Practice里有讲解,不过有点过于精炼了。
有个梨UGlee
2019-11-02 02:06:11 发布
截图是Amazon DynamoDB文档,注意中间有一句很惊人的话:绝大多数良好设计的应用只需要一张表。

在最佳实践一节有一个many to many的例子,使用了一个设计模式:adjacency list。把两种结构的数据混在一个表里。文档链接:网页链接

文档中的schema图示有点模糊,stackoverflow上有更详细的解释:网页链接

看懂这个例子就能理解Dynamo的本质。它不是根据数据结构的模型意义上的关系设计表结构的,而是根据你需要如何查询数据来设计表结构的。这个设计模式应该没有悬念的成为DynamoDB的最为重要的设计模式。它确实是很惊人的,对于像我这样没怎么用过DynamoDB的人来说(也没怎么用过bigtable,我估计两者是很接近的)。

看起来很tricky,但确实解决问题。DynamoDB支持transaction,意味着同时连续更新几条记录以保障关系的完整性是可以做到的。
有个梨UGlee
2019-11-01 19:06:11 发布
读Packt的书都比读aws的文档快,aws的文档简直是战争与和平。
有个梨UGlee
2019-11-01 19:06:15 发布
NoSQL的many to many relationship的schema简直堪称神乎其技。
有个梨UGlee
2019-11-01 14:06:15 发布
问一个肥肠basic的问题,基于mqtt的聊天室,如何设计topics?
有个梨UGlee
2019-10-31 23:05:25 发布
看微博介绍坚果外观设计还可以的,定制软件的设计就惨不忍睹了,过于繁琐;但卖不出去也基本上是肯定的,这年头渠道都没了。
有个梨UGlee
2019-10-31 17:05:30 发布
aws的自动化整个一大号php,全是模板语言。
有个梨UGlee
2019-10-31 17:05:30 发布
每天都能学到一点新知识。今天知道了aws china不支持lambda的environment variable。
有个梨UGlee
2019-10-31 14:05:30 发布
不知道在SAM出现之前aws lambda用户是怎么撸代码的,还是说全手工撸CloudFormation然后手写自动化部署,对应aws的CodeDeploy功能。
有个梨UGlee
2019-10-30 00:00:00 发布
网易简直是闲的蛋疼,Bitches Brew变成了******* Brew。
有个梨UGlee
2019-10-30 21:05:13 发布
这个在console里面打出来的啤酒?图标是肿么回事?
有个梨UGlee
2019-10-30 00:00:00 发布
你大爷的,aws中国连创建lambda applications也妹有,这是只能一个一个lambda修改吗?喷了!
有个梨UGlee
2019-10-30 00:00:00 发布
Amazon如果拿下Oracle,未来就只有两种语言了,Java和JavaScript。
有个梨UGlee
2019-10-30 00:00:00 发布
ufs价格快追平emmc了,意味着廉价arm笔记本可以更廉价了,可是rockchip和allwinner竟然连支持ufs的U都妹有,简直喷了。
有个梨UGlee
2019-10-26 22:05:07 发布
大家都在看易烊千玺,我在看aws CodeDeploy。
有个梨UGlee
2019-10-24 17:06:26 发布
AWS最值得吹捧的服务是它的cloud formation,可以一键把所有的资源和服务拉起来。
有个梨UGlee
2019-10-23 02:05:38 发布
鄙视js的一些垃圾语法设计和无聊的类型cast是没问题的;鄙视js的全栈也情有可原;但是鄙视js的异步非得去搞线程模型的,就是不理解large scale的serverless编程最终必须回到事件模型上;什么多核计算效率之类的问题只有系统级编程是个事儿,架在lambda上跑你管他多少个核呢?那是infrastructure该操心的。
有个梨UGlee
2019-10-22 18:05:49 发布
另外一个基于CA证书管理keyserver/公钥证书池的想法也说一下。

一个手机,一个nas,和云,在建立一个pool的时候创建一个密钥;然后使用Shamir Secret Sharing或类似算法把密钥split成3份,三方各持一份。如果要签发新的证书,手机有一份,还需要去云取一份,可能需要一个手机短信或者Email之类的验证;然后就合并了完整密钥可以签发新证书;如果手机的部分丢了,可以利用云和nas上的恢复(需要手机和NAS近距离通讯,例如通过蓝牙);三者中两个丢失或者泄漏才算完蛋了。

不知道用这样的方法是不是可用?
有个梨UGlee
2019-10-22 15:05:56 发布
问一个安全问题。

如果有一组设备a1, a2, ...需要建立一个简单的基于证书的互信,不用CA或者web-of-trust,每个设备有自己的证书;

所有的公钥证书存在一个外部的池子里,例如云服务器上;初始建立这个池子需要两个设备互相签名;之后往池子里添加设备都需要已有设备签名(任意一个);

目的:不信任云服务器;只要所有的设备的密钥都不曾泄漏,云无法伪造池子内的公钥证书。

请问是否有什么漏洞?欠妥的地方?不用CA是因为CA的密钥没法保管;不用web of trust是因为web of trust太麻烦了,实际应用中需要签名的设备数量不会太多,几个到几十个,所以想有一个简单的办法。

有个梨UGlee

既已高远,何不淡泊。

1204 65225 34990
关注粉丝微博