说了再见 / 软件

毕竟我不是一个很有毅力的人,也不是一个做事很快的人。我做不到像“电脑玩物”那样,两三天就更新一篇图文并茂的软件介绍;也做不到像“GTDStudy”那样,持续地更新关于同一个主题的文章。所以,我写过的软件不多。

而这其中,回忆最多的,就是BooguNote和Tabbles了。

BooguNote是一个树状笔记软件。所谓“树状”,并不是指一般笔记软件那样可以建立分类和文章的层次结构,而是指“笔记”本身就是有层次的。“笔记”本身就是“一棵树”,它的每个节点,都是这篇笔记的一部分内容。除了独有的树状笔记之外,BooguNote还提供了强大的抓取功能和几近疯狂的快捷键设定;笔记的内容也可以直接导出为思维导图或是保留了树状结构的HTML文件。

Tabbles,则是一款文件管理软件。它采用了类似Windows在7中引入的“库”的概念,用户可以将文件添加到虚拟的文件夹(Tabble)中。同一个文件可以被添加到多个Tabble中,而Tabble支持数学上的集合运算,这使得筛选文件变得更加容易。从某种程度上,Tabbles实现了WinFS的目标。

为这两个软件所写的文章,也是我博客经历中的高峰。

为BooguNote写的教程(BooguNote全解),可能是我花费时间最长、花费精力最多的文章,也是我发布过的字数最多的文章。截图软件的编辑功能满足不了我,于是每张截图都在Fireworks里进行编辑;文字的部分一写就停不下来,最终写出了5000多字;文章上线之后,还使用Illustrator排版,制作了PDF的版本,放在了软件的官网上。

而为Tabbles写的介绍,则被《电脑爱好者》杂志的编辑看到并且约稿——这是我第一次,也是至今为止唯一一次赚到稿费。

这些,都发生在2010年。

而现在呢?

BooguNote的作者在一年前就放出了源代码,自己则放弃开发;BooguNote的论坛里,帖子也寥寥无几。

Tabbles多年未用,并不清楚开发状况如何,但官网上的操作系统支持列表里,仍然没有Windows 8。

3年的时间,学生变成了上班族,5000字变成了140字。

无数事物消逝而无数事物新生。

也许,见证过,就是幸运。

说了再见 / 序篇

——曾经能够很轻松地写出5000字一篇的博客,而现在,有时就连140字也无法填满了。

我已经记不得是从什么时候开始写独立博客了,不过我还记得曾经在2008年的暑假为独立博客的事情通宵了好几天;还记得用过的第一个主题是来自zeuscn.net的D&Z Theme;还记得文章被著名博客引用之后访问量一夜之间上升了百倍……

曾经,每次登录QQ,都能看到yo2的群有几百条记录;
曾经,每次打开WPG的论坛,都能看到一大堆的新帖子;
曾经,遇到一个喜欢的软件,可以一口气写出几千字来介绍它;

但是那些都成为了过去。熟悉的服务下线了,热闹的群沉寂了,喜欢的软件停止更新了。而我所认识的很多成功博主,也随着大学毕业离开了这个圈子——是的,毕业那天发生的,可不仅仅是失恋。

偶然在硬盘上翻出以前文章制作出来的PDF,对那个时候的怀念突然涌了出来。每次与有着多年游戏经历的老玩家聊天时,我都会说我不是一个怀旧的人,不会怀旧。也许,是因为我的童年里并没有电子游戏的存在吧——而博客,却发生在我的大学生活中,伴随了我最美好的一段时光,也带给了我那么多志同道合的朋友。是的,我怀旧了。

说了再见 / 才发现再也见不到

那就把它写下来吧。

事件驱动编程与反应器模式的区别

[For the record] 尽管删掉了被黑的Wordpress博客,还是觉得应该把这篇留着。

Stackoverflow原帖:What is the different between even driven model and reactor pattern

[提问 by Howard]

在维基百科(英文)Reactor Pattern的条目中,有如下描述:

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. 反应器模式是一种事件处理模式,用于处理从一个或多个来源同时分发到服务处理器的服务请求。

文中举了一些例子,例如node.jstwistedeventmachine。但是在我的理解中,上面这些都是流行的“事件驱动框架”——于是它们也就是“反应器模式”的框架?如何区分这两者?或者说,它们是相同的么?

[回答 by Jean-Paul Calderone]

“反应器模式”“事件驱动编程”要更加具体——它是在使用事件驱动方法编程时的一种具体的实现方式。但是在平常的交谈中,这个词的精确意思并不常用。所以,你应该小心使用这个词,确保你的听众能正确理解你的意思;同样,当你遇到他人使用这个词的时候,也要留意你的理解是否与他人的本意有所偏差。

看待反应器模式的一种方式是将其与“非阻塞操作”密切联系起来。当某个操作可以不被阻塞地完成时,反应器就会发出通知。例如,select(2)可以实现反应器模式,以便使用标准的BSD Socket API(recv(2)send(2)等等)来读写socket。例如,当一个socket在系统内核中的接收缓存中有字节可读的时候,也就是说,你能从中读取到数据的时候,select就会立刻告诉你。

在考虑这些概念的时候,另一个你可能会感兴趣的模式就是“前摄器模式”(Proactor Pattern)。与反应器模式正好相反,前摄器模式不考虑操作是否能够立刻完成,而是直接开始操作,使其异步执行,并等它完成之后再安排分发事件通知。

Windows I/O Completion Ports(IOCP)就是前摄器模式的一个例子。当使用IOCP在一个socket上进行发送操作的时候,该操作会立刻开始,无论这个socket的内核发送缓存是否有空间来容纳数据;当WSASend调用完成的时候,发送操作才会继续(在另一个线程里,可能是在一个系统线程里)。当发送操作真的完成了(即要发送的所有字节全都已经被复制到发送缓存之后),提供给WSASend调用的回调函数就会被执行(在应用程序的新线程里)。

这种发起操作并在完成时得到通知的做法,正是异步操作思想的核心。而非阻塞操作,则是只有当操作可以立刻完成的时候才发起操作,否则将一直等待。

这两种方式都可以用来进行事件驱动的开发。使用反应器模式的时候,程序将等待例如“某个socket可读了”的事件,当事件发生时,就去读取;而使用前摄器模式的时候,程序则直接发起读取的操作,并等待读取结束事件的发生(然后对结果进行处理)。

严格地说,Twisted误用了Reactor这个词。The Twisted reactor基于select(2)并以非阻塞IO的方式实现,这几乎就是一个反应器;但是,它提供给使用者的接口是异步的,这一部分更像是前摄器。Twisted还有一个基于IOCP的反应器,这个反应器为应用程序提供的也是异步的API,并且使用了前摄器式的IOCP API。它是一个混血,而且在不同平台上有着不同的实现细节,因此,用Reactor和Proactor来描述都不准确。不过,由于twisted.internet.reactor里提供的API基本全都是异步API,而非“非阻塞”API,用Procator来称呼Twisted应该会更加合适。

[回答者追加评论摘要]

select(2)是非常底层的,而且很难使用。当有很多个事件源的时候,它还不够高效。现代的系统提供了功能相同但更加高效的API,如/dev/pollepoll等。Twisted及类似的库的好处在于,它们提供了对各种不同实现方式的抽象,使得应用程序可以使用一套统一的API,同时仍然能享受到底层系统提供的高效API的支持。

select(2)epoll(4)的比较,可以参考这篇Q&A:Caveats of select/poll vs. epoll reactors in Twisted

Hello World, Hello Hexo.

你好世界,你好Hexo。

是的,我又折腾了。这个博客现在托管在Github上,使用Hexo生成。

之前的Wordpress博客被黑了。我没有装近期爆出大漏洞的wp-super-cache,还是被黑了。我用的主题文件内容被替换成了意义不明的php代码,我的用户名被修改成了别的名字——而WP后台是不允许修改用户名的。Wordpress这东西的安全性,看上去是越来越差了。

所以我抛弃了Wordpress,再次转向“静态博客生成器”。这次的选择是Hexo,一个用Node.js开发的静态博客引擎。与成名已久的Octopress相比,它的名气小得多;不过,得益于微软和Node.js官方的良好合作,在对Windows的支持上,Hexo比Octopress要好太多了——从安装、配置到部署,遇到的问题比当年少得多,解决起来也相当轻松。

使用过程中遇到的几个小问题:

  1. 配置文件里填写Github的Repository时,最好使用SSH方式的链接;至于SSH的配置,最简单的方法就是装一个Github官方客户端。
  2. Github官方客户端的Git Shell用的是Windows Powershell而非普通CMD,它不会读取系统的PATH,而是需要单独设置。
  3. 如果写中文乱码,将.md文件保存为UTF-8 without BOM即可解决问题。