2013-05-26

所谓收敛

之前一直觉得互联网之于个人来说是无限的.
毕竟现在几乎所有东西都能够通过网络访问.

但是打开chrome看到最近访问的时候,才醒悟过来,可能并不是这么简单直接的逻辑.

虽然每天可能访问着各种不同的链接和内容,但是,细想之下,其实起点都是个有限集.
所有内容不过是非常有限的几个地方展开的.

与其他普通链接不同的是,它们自己算是一种某种程度上的平台,或者说协议.
比如email,比如rss,比如tweets,比如某些视频站,比如某些论坛.

虽然看上去有着各种不同的内容和社区准则,但实质作用不过是导入一些具有鲜明特性和分类属性的链接.

某做程度上的对graph的partition,或者说某做mapping或者transform.

于是所谓的导航网站的意义就很明显了.
一个structure的特解,减少的借入构造成本.

把这个应用到移动方面的话,似乎也差不多.
毕竟这是本质需求.

所谓获取信息的成本问题,加上本身现有移动环境下带来的交互限制.

尽管,平板之于手机的话,可能更类似于传统的桌面web环境.
但不可否认的依然是操作交互上存在天然的局限性或者说区别.

抛开这些,另一个问题在于,app的迁移成本.

传统web在具体到各个网站和服务的时候,也存在迁移成本问题.
但相较于web来说,问题可能相对简单些.
毕竟,多数时候,只是替换一个link而已.

而app的的特别之处在于,除了自身服务的迁移成本以外,还有替换app的成本.

考虑极端情况下,一个移动设备只能安装一个app的情况.
在这种情况下,后来的app如果想要提出旧有app的话,难度无疑比web服务的替换要打得多.
web服务至少还可能同时使用,但移动环境下的app可能就会受限与物理因素,使得连尝试的入门成本都变得异常的高.

换个角度看的话,就是app的lock down作用非常地明显.

于是,加上web固有的,人只需要少数入口/协议的观点,在移动平台的交互没有大的革新的前提下,所谓平台的价值将会非常明显.

这里的平台可能并不是一个传统的诸如Facebook之类的载体.
它可能只是一个具有相对连续性的东西.

即,即使app改变了,它依然存在.

比如twitter类的关系,即使客户端变了,但是本质服务的内涵不受影响.

所以,从这个层面来说,平台的含义指的是这种不可变的连续性.

于是,如果这个想法是对的,那么可以预见的未来将是更多的以协议为基础的交互.
比如新闻阅读类回归RSS,视频类衍生类RSS的交换标准.

毕竟,如果市场是竞争的,那么必然会有层出的竞品出现.
而如果竞品足够优秀,那么就意味者会有不断的安装和卸载事件发生.

如果不是的话,由于lock down效过,进入门槛将会变得不可想象地高,使得市场只留下有限的几个参与者.
而一旦形成这种垄断局面的话,也很容易地会催生相应的协议,以使得小参与者们能联合起来形成规模效应.

于是,无论怎么看,最终都将会衍生一系列的交换标准以帮助和保证市场及其公平性.

2013-05-18

Schedule

前段时间用go把zeromq和leveldb粘合在一起,写了个玩具性质的queue(http://goo.gl/m3anm).

于是,一个纠结了很多次的问题又出现在了眼前.

站在API的角度来说,zeromq和levelddb都是可以异步的.
于是,使用上的一个问题就是,如果全部采用异步接口,那么就存在一种情况,所以调用都没ready的情况.

这时候,要么自己sleep一段时间,要么burn CPU.
就像没有epoll之前,如何使用poll一样.

所以这个问题的矛盾之处在于,异步或者说time sharing的目的为了用尽可能少的资源,做尽可能多的事情.
也就是减少浪费.
而,一旦出现某个时期,所有工作都是闲置状态的时候,却多数不得不做稍显浪费而又必须的loop/poll.

出现这个问题的本质原因,是站在上层角度来说,没有像系统一样的来自外界的唤醒重入机制.
像epoll,可以由外界的硬件通过信号触发处理例程的重入(尽管实现上,并不确切,但至少理论上是可以让CPU完全闲置,而不会有什么副作用的).

于是scheduler需要的是一种离开block状态的通知机制.

这个通过把schedule注入到signal handler里也是可以实现的.

问题是,不是所有的可能block的地方,都存在这种ready状态的回调.
因此,多数情况下的选择就是burn cpu了,所能做的优化只能是尽可能减少无谓的poll,同时尽可能降低调度带来的延迟.

毕竟在这种情况下,要么是poll早了poll多了,要么就是poll晚了.

目前go的sysmon的做法是采用2us的幂次增长,最多10ms的延迟调度,外加一个对网络的poll.
以期望尽可能地实时调度.

这算是一个很工程化的解决方法,能解决一部分问题,但不根本.
因为它依赖于这个间隔时间的调整.

事实上,许久之前自己也写过一个类似的东西(http://goo.gl/8ymEZ).
它的其中一个问题就是调度周期带设定.
尤其是面临一些繁忙程度比较浮动的情况.

而且,对于再上层应用的应用来说,就算go本身提供了这种机制,并且能够良好工作,自己写的时候也一样会遇到类似的情况.

就像开头说的,如果应用本身都是异步的,那么自身也需要有调度.
比如zmq_recv完了,发现没东西,那么可以直接一个goroutine出去.

在多数情况下,这个没什么问题.
但是如果其它goroutine也是这样的不ready状态,那么无非等价于一个空的for循环.

这里能想到的就是引入一些本身有block属性,同时能触发调度的.
也就是chan.

之前尝试过在for里加gosched,效果没什么改善.
因问题的本质是空闲造成的,gosched的结果不过去取出下一个空闲的goroutine而已.
做一些看似有用实则差不多的事情.

当然,如果都是纯粹的go code的话,也许不需要.
因为go"保证"了所有时刻都是在有效率地消耗CPU.
毕竟,任意go,或者chan等逻辑上的block操作都会触发调度.

但是遇到syscall以及cgo的话,就可能不太一样了.

cgo本质上都是syscall.
而syscall的问题在于,它会让出当前的P,然后调度器会为此多一个M去执行go code.
也就是,syscall的后果就是,多出一个worker线程.

虽然原则上来说,只有非常频繁的syscall才会导致线程数异常增长.
而且,即便如此,也可以通过lock或者buffered channel等限制syscall的并发数量.

但这个跟这里的问题关系不大.
cgo在这里的问题是,如果你的go code(main)跑完了,那么整个程序就结束了.

所以,这就要求go code里有一段"永远"block的调用.

如果是永远block的调用的话,对于默认单P/逻辑M/逻辑线程的go来说,就是以后都没有可用P了.
于是,即使cgo返回,由于没有逻辑上可用的P,程序也不会继续下去.

因此,它需要的是一个带yield的语义的调用.

这个yield,回到前面的话题,就是要考虑怎么尽可能不浪费而又实时.

于是,只要有着尽可能有效利用的想法的话,就逃避不开调度这个问题.
而多数情况下,都只能有很工程化的解.

聊聊卡布里尼

最近看了部片叫卡布里尼,算是可能这段时间来比较有意思的一部电影. 故事也不算复杂,就是一个意大利修女去美国传教,建立慈善性质医院的故事. 某种程度上来说,也很一般的西方普世价值主旋律. 但是如果换一套叙事手法,比如共产国际的社会主义革命建立无产阶级广厦千万间的角度来看的话,也不是...