Good good study, day day up

aleung的学习笔记, aleung的idea

Jekyll

| Blogging

用 Jekyll 作为内部技术文档库

去年在公司的产品开发团队中推行了使用 Jekyll 静态网站生成工具来写内部技术文档,大半年下来,效果还不错。

内部技术资料的共享和维护以前一直是个问题。开始用 Office Word 正正规规的写设计文档,维护成本太高了,往往是代码已经翻天覆地变化,文档里都没有反映出来,大家不愿意更新。而且查找起来也不方便。后来推行敏捷方法,不想让文档工作那么 heavy 了,于是用 wiki 来记录。Wiki 的问题是信息非常碎片化,大家很随意的添加新页面,整个 wiki 就像一个草稿本,写得很没有系统。网状的超链接导航令读者很迷茫,不知道需要的信息入口在哪儿,有些隐藏得很深的页面没有几个人知道它们的存在。Wiki 的在线编辑体验也不是那么好。

Jekyll 是个静态网站生成工具,采用 markdown 语法来写内容,根据模板生成 HTML 页面,发布到一个 web 服务器上,就可以用浏览器在线查看内容。Jekyll 通常用来做 blog 系统,但它用来做有组织的内容发布系统也是完全胜任的。我基本上就是仿照 Jekyll 官方文档 的风格和结构来组织我们产品的内部技术文档库。

使用 Jekyll 优点首先是编写方便,markdown 是个轻量的标记语言,上手简单,语法易记,而且有不少编辑工具支持。即使没有渲染成 HTML,也是直接可以阅读的,比起奇奇怪怪还各自不同的 wiki 语法好写多了。

在模板做得好以及安装合适的插件后,生成的文档显示效果相当漂亮,格式效果也很丰富。而且,我们使用了 plantuml 插件,可以直接用文字的方式UML1,比起以前用其他工具画图,截图,再嵌入文档这种方式方便多了。

技术文档库的原始文件是文本格式,用 git 来做版本管理,不用担心大家同时编辑保存时会相互覆盖的问题,修改历史也很清晰。大家都是程序员,本来代码就是用 git 来管理的,文档也用 git 管理自然是很顺手的事情。使用 jekyll-post-revision 这个插件,能够在生成的页面上显示修改历史记录。

通过 jekyll-lunr-js-search 这个插件,能为站点提供全文搜索的能力,这也是相当方便的功能。

在 Windows 上安装 Jekyll

Jekyll 是用 Ruby 开发的,在 Linux 和 Mac OS X 上安装使用都很简单,在系统中有 Ruby 环境的前提下(Mac 是自带的,Linux 的各种发行版都会有安装包),照着官网上的介绍,几个命令就搞定了。但是,在 Windows 下就不是那么简单了(顺便再黑一下 Windows,不使用 Microsoft 技术的开发者都应该离开它)。

在 Windows 上装过几次 Jekyll,可以写点教程减少大家摸索的时间。大致参考这篇 Run Jekyll on Windows

安装 Ruby

首先需要安装 Ruby 环境。从 http://rubyinstaller.org/downloads 下载 Ruby 2.0 和 DevKit,安装 Ruby,然后将 DevKit 解压到 C:/RubyDevKit,在命令行运行下面指令完成安装。

1
2
3
cd C:\RubyDevKit
ruby dk.rb init
ruby dk.rb install

安装 Jekyll 相关的 gem

Gem 是 Ruby 的包管理工具。在命令行执行gem install可从互联网的仓库直接下载和安装需要的包。如果需要代理,需要先设置环境变量http_proxy,如不需要则忽略第一行。其中,jekyll这个 gem 是必须安装的,其他的视乎环境、配置和使用的插件,可能需要装,可能不需要装。

1
2
3
4
5
6
7
8
9
10
set http_proxy=http://my-proxy:8080

gem install jekyll

gem install kramdown
gem install pygments
gem install nokogiri
gem install coderay
gem install wdm
gem install json

如果在安装过程中出现 SSL 错误,从这里可以找到解决方法。

使用 Jekyll

Jekyll 的相关操作都是执行jekyll命令进行。后面的基本上就是看官方文档慢慢折腾了。

制作 jekyll.exe

上面的步骤还是有点繁琐。我们公司里的都是 Java 程序员,在电脑里装个 Ruby 环境也没有其他用处。为了推广使用,简化大家的操作,做一个 portable 的 Jekyll 可执行程序会更好。

制作的步骤基本上参考这篇 Building Jekyll.exe for Windows

首先要安装 OCRA。可能还需要安装 psych,bigdecimal 这些 gem。

1
gem install ocra

解开 jekyll 到一个临时目录:

1
gem unpack jekyll

修改bin/jekyll,在开头增加几个依赖声明:

1
2
3
require 'nokogiri'
require 'jekyll-watch'
require 'wdm'

生成 exe 文件:

1
ocra --add-all-core --gem-all bin/jekyll lib/jekyll/mime.types lib/site_template/**/* lib/site_template/*

做出来的 jekyll.exe 需要测试一下,看看各种命令是否都能正常。视乎配置和使用插件的不同,可能需要增加更多的依赖声明。以上只是我的环境的例子,不一定适用于所有场景。

最后,我知道大家都还是懒得衣来伸手饭来张口的,就提供一个编译好的 jekyll.exe 下载,支持 kramdown 和 coderay。但还是那句话:不一定符合你的环境。


同事们关于 FP 语言的讨论

| Haskell, Scala, SoftwareDev

之前在公司里一来一往的邮件讨论,被江南白衣集成一篇收录到他的博客里,读下来还蛮有意思,转过来,以下为全文引用。其中的梁君就是我啦。

缘起

达夫君

利用 GitHub 统计分析编程语言发展趋势

第一轮讨论

梁君

增加的Java的项目里,不知道有多少是与Android相关的呢?

Scala最热门都是在意大利城市(Milan, Rome, Florence, Naples,Turin),很奇怪,意大利软件业不发达。于是查了字典在意大利语里scala是scale(英语)的意思,应该跟编程语言无关。排除之后排首位的就是 San Francisco和San Jose,硅谷地区。

最近几天在看 Haskell,真是非常有趣的一门语言。 于是也在Google Trends上看一下,搜索Haskell最热的城市是 Gothenburg,第二是Utrecht (因为乌特勒支大学?)。

2014年热度,按国家排序,Haskell最热也是China! 考虑到中国已经屏蔽了Google,这个结果令人吃惊。在国内Scala, Haskell也不是那么热门吧?程序员人口基数大?

雄君

Haskell应该是所有程序语言里面被神化的最厉害的吧。有种说法,Haskell可以让你变成一个更好的程序员,即便你不用它,好像还有本书名就是这个。感觉看几本Haskell书就能变成高手似的,快变成宗教了都。。。。

梁君

Haskell应该是一种研究型/教学型语言吧。

据说是纯粹的FP,我现在看它是想试试强迫一下自己使用FP的思维模式。

那篇 WhyWhyFP 不错。 里面,看到一些话(虽然不算是那篇文字的主题):

The key is the word better. It is not the same as the phrase more powerful. it is possible to make a language “better” by removing features that are considered harmful, if by doing so it makes programs in the language better programs.

关于 better 与 powerful 的思考,不是功能越多就越好。用在我们的产品上也是一样啊。

哥德堡的Haskell教授

赵君

Gothenburg研究Haskell的那个人好像是Richard君的教授。感兴趣的可以问问Richard的感受。

范君

Richard说的:

Mr Hughes is a very smart guy. And his homepage hasn’t changed since I had him as a professor : http://www.cse.chalmers.se/~rjmh/

国外大学很多都是用Haskell,大老板之前去大英帝国读研也是用它。

FP做题大赛

韶君

我好奇看一下,“证明即程序、命题为类型”,这就是一门数学领域的领域语言,难怪学院派对它宠爱有加,一边证明一边编程,逼格高啊

有个网站号称趣味学Haskell: HASKELL 趣學指南 1

Step by step 学了一下Haskell,居然停不下来,无论写还是读,都像在玩puzzle game,都想找回以前的数学课本来复习一下。我想不用也能让你成为更好的程序员此话不假,就是让你恶补一下已经还给老师的数学概念。

给个零零漆的经典应用题大家思考一下:有一个农场,鸡的数目是鸭的四倍,但是鸭又比猪少九只,鸭和猪的数目是六十七只,请问农场所有动物的脚加起来共多少只?

雄君

感觉这跟你的学习方式关系更大,跟语言关系不大的。你也可以用Scala去做SICP的习题,同样有这种感觉。

梁君

不挑起具体语言之争。韶君的例子应该是说明FP给人带来耳目一新的感觉。

另外,我感觉那本书 (Learn You a Haskell) 用来做FP入门真的很好,之前看过一些Scala的书都没有那么清晰的理解。

顺便做做那道题目:

1
2
Prelude> head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67]
442

韶君

我原来写的是

1
head [a*2+b*2+c*4|a <-[1,2..], b <-[1,2..], c <- [1,2..], a=4*b, b=c-9, b+c=67]

结果不会结束,除非数组加上限,有空找你理解一下。

确实是FP带来的感觉,相信Scala也可以带来这个感觉,只不过如果我用Scala就不自觉地当Java来做了。

达夫君

我原来也是将Scala当Java来写。但是当你将Java的语法忘了差不多了,Scala就入门了:)

其实只是个老问题,就是平常没机会看Scala的代码,没有好的example参考而已。 看别人的代码多了,也就习惯了。

用 Scala 解那道题:

1
2
3
4
5
6
7
8
9
val d = (1 to 67) toStream
val feet = for {
  d1 <- d
  c1 = d1 * 4
  p1 = d1 +9 if (d1 + p1 == 67)
} yield {
  (c1+d1) * 2 + p1 * 4
}
println(feet.take(1).force)

梁君

Scala应该增加一种纯FP模式,当打开这个选项的时候,任何不符合FP的写法都报错(或者warning)。

米君

沒電腦,裸寫一段 Python,不知道對不對:

1
print map(lambda x: x*2 + x*4*2 + (x+9)*4, filter(lambda x: x+x+9 == 67, range(0,67)))[0]

看起來還是 Haskell 的最有數學味。

邊打邊爐邊研究,或者還可以這樣(不知道對不對,大意如此):

1
print (x*2 + x*4*2 + (x+9)*4 for x in range(0, 67) if x+x+9 == 67)[0]

據說這樣有 lazy evaluation,map 和 filter 不知道有沒有。有明白人指點一下嗎?

韶君

FP的思路就是“是什么”,指令编程的思路是“做什么”,从这个角度看 head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67] 这个最优雅了,基本上把题目复述一遍而已

雄君

米君,你已经线下把三元方程转成一元了,这个是作弊吧,不算。

Haskell的 lazy evaluation 在这么小的程序里面也会搞出无限循环的bug,这是它没法商用的最大原因之一。

我发一个Clojure的,也符合数据的解方程思路。

1
2
3
4
(first (for [p (range 1 67)
             :let [d (- 67 p) c (* 4 d)]
             :when (= d (- p 9))]
         (+ (* p 4) (* d 2) (* c 2))))

梁君

这个我忍不住要说说了,上限没有在原题中给出,需要推理才能得到的。Haskell的程序里是没有设上限的:a <-[1..], b <-[1..], c <- [1..]。 你们写的其他程序都是有上限的:p (range 1 67)x in range(0, 67)(1 to 67)

用这个来说Haskell会搞出无限循环的bug是不是有点冤枉了?

p.s. FP的理论在那里,现代的语言都或多或少吸取进去了,只是用什么语法形式的问题,纯粹一些还是要跟原来的特性做妥协,大家也都相互借鉴。除了Java最不思上进。

看上去Clojure的语法最像Lisp。

米君

不服上訴。哈哈。

這樣呢?算不算真三元?(已經盡力了。除非改成一元,否則range 好像是繞不過的坎,如果改成無限列表也是一樣會死循環。)

1
print iter( c*2 + d*2 + p*4 for c in range(67*4) for d in range(67) for p in range(67) if c == d*4 and d == p-9 and d+p == 67).next()

Clojure的版本和Java看上去很像啊。唯一不同大概就是 lazy evaluation 吧。 另外,雖然定義了三個變量,但其實只有一個是真正的“變”量,所以還是一元。

1
2
3
4
5
6
for ( int p = 1; p <=67; d++) {
  int d = 67 - p;
  int c = d * 4;
  if ( d == p - 9 )
    System.out.println( c*2 + d*2 + p*4 )
}

雄君

其实完全不是那么一回事,Scala和Clojure里面的for不是循环的意思,达夫之前解释过。这是Java程序员转FP的第一重障碍。另外,Clojure这段代码绝对没有lazy evaluation,如果需要Lazy,Clojure必须要明确指定使用Lazy seq。

Python和Java的表达能力不可能赶上Lisp的,超过Lisp表达能力的语言还没有发明出来。

最后一轮讨论

雄君

Clojure是一个Lisp变种,也是目前唯一的一个商业化的Lisp系语言。

Haskell 是 lazy evaluation by default 的语言,全世界几乎独此一家了。这个特性导致程序运行时,时间和空间都是不可预期的,基本上没有企业敢用。

Haskell又为了程序在逻辑上的predictable,从语言成面回避side effect,结果连个随机数生成都搞不定,发明monad来解决这个问题。问题是monad这么复杂的东西,用Haskell开发竟然是必须掌握的技巧,这很恐怖啊,哪找程序员?

这语言真的是只能看的。

韶君

Haskell我觉得商业上想取得成功确实不容易,但我不觉得作者想这样做,说商用,有哪种语言比Java更成功呢,指令语言也没那么容易出错,因为指令语言只有想不到,没有做不到,想取得商业成功就意味着妥协,从这个角度,我更看好Scala。

达夫君

估计等大家要看Java8的时候就需要考虑是升级JDK到8呢还是换Scala了。

梁君

Haskell 就是一门教学/研究型语言,开个学术会议,几个老家伙聚在一起,说不如我们设计个语言来显示一下FP多牛B吧。商业成功不是它设计的初衷 (后来其他人怎么想是另外一回事)

At the conference on Functional Programming Languages and Computer Architecture (FPCA ‘87) in Portland, Oregon, a meeting was held during which participants formed a strong consensus that a committee should be formed to define an open standard for such languages. The committee’s purpose was to consolidate the existing functional languages into a common one that would serve as a basis for future research in functional-language design.

才发现BASIC不是我唯一的入门语言,我刚学电脑的时候还看过Logo语言,这么说我也是一开始就接触FP的啦。

对Java程序员和已经大量投资于Java的软件企业来说,应该是Scala最有价值。

雄君

我是前几年被人忽悠后花了好几个月学习Haskell,还想用它做项目,现在已经弃坑了。

诗一首

孤独时

孤独时我不喜欢使用语言。
一头熊和一只鹦鹉坐在
跷跷板的两头
跷跷板朝一头翘起。很多东西
没办法称量,我是熊你们是鹦鹉。
我是这头熊我不使用
你们的语言。

余怒,2003.7.20

  1. 英文原版为 Learn You a Haskell for Great Good!。有电子书,简体中文纸板也出版了。

Haskell

| Haskell, SoftwareDev

2014年断断续续学了一阵子 Scala 语言,Scala 真的不错,将面向对象和函数式编程两种范式结合得很好,对 Java 程序员非常友好。不过,从学编程开始就受命令式编程的思想的浸淫,要使用函数式编程的思想相当困难,思路转不过来,而 Scala 又不强迫你用 FP,所以写出来的程序基本上还是命令式的。不少人都推荐学 Haskell 作为函数式编程的入门,作为一门学院派的语言,它非常纯粹,有助于掌握函数式编程的思维方式。于是开始读 Learn You a Haskell for Great Good,这真是本入门好书,从头开始一点点的理解接受函数式编程的思路。学 Haskell 的感觉非常有趣

不过那本书只是讲语言特性和思想,没有讲 Haskell 的运行环境和使用。上网收集了一些资料,记录下来。

Haskell (缺省)是编译成 native code,并非运行在托管环境下,因此开发出来的程序就像 C 的一样直接可执行的 binary。Haskell 程序需要依赖于 Runtime System (RTS),RTS 提供了内存管理,GC,轻量线程,并发等等功能的支持。包括 RTS 和其他的依赖到的 library,缺省都是静态链接到可执行程序中的,因此编译出来的程序体积会比较大。但现在 GHC 也已经支持动态链接了,如果使用动态链接,则要求运行环境中需要已经安装了 GHC(有 RTS)。在这方面,Haskell 跟 Go 差不多,都是直接得到 native 可执行程序,分发和部署会简单一些。

Haskell 的编译器叫做 Glasgow Haskell Compiler (GHC),它包括了 compiler,boot library 和 runtime system (RTS)。编译器支持多种 backend,除了可以生成 native code (机器码),也可以产生 C 语言源代码(供跨平台移植),或者 LLVM code,(供后面接 LLVM toolchain 使用)。

做应用开发不太可能什么都从头做起,必然要依赖第三方的函数库。Haskell 世界里的包管理和 build 系统叫 Cabal。另外有个工具 Cabal-Install 负责下载 Haskell package 源代码、编译、安装和注册到 GHC 的整个过程。共享的包存放在 Hackage 这个在线仓库中。

Reference: The Architecture of Open Source Applications - GHC

大鹏新年马拉松

| Running

Pacer数据丢了,没法分析心率和速度 :(

净成绩 4:17:47,比广马要好些。之前训练很少,按照玩玩的心态去跑,没有设定时间目标,也没有预定配速,就按照舒服的速度跑。

起跑后速度不快,大家的速度也平均,不像其他赛事一样起跑速度都很快,应该是因为只有全马,大家都是有经验的。开始几公里步速大概在5’50”上下,感觉跟平常训练很像,步伐轻快,心率也没有一下飙高。太阳没出来,有点风,罩着雨衣到8km 才脱下。

十几公里那段跑得比较舒畅,步速也不知不觉加快到5分十几秒的样子。这段落偶有小上下坡,新柏油路面,很舒服。18km 吃能量胶,以免20km 后能量不足。这时我还挺乐观的以为能跑进410。

过了半程 开始觉得膝关节不适,比以往出现得早太多了,而且二十多公里后开始变成水泥路面。心肺状态倒是很好,基本不喘气。

25km 补给点吃了盐丸和香蕉,26km 经过水头,有些民众加油,气氛不错。27km 后有点疲累了,28km后一个陡坡,怕太耗体能,走了后半段。

30km 那段很多人都在走路了,只要坚持跑就能不断超人,距离拉得很开,有些时候就是一个人在跑,前面很远都没人。这时跑得吃力了,速度在6分左右,但感觉很慢。不断的期待什么时候能到往大亚湾电站的路。小腿也有抽筋感觉,在医护站喷过云南白药。这段路上又吃了一个能量胶。

31km 后转弯拐向大亚湾核电站方向,对面有折返的人,观众也多些,心理上很快就跑完了折返段这两公里。

然后就一直惦记着38km 前那个大上坡,实际上上坡从33km 就开始了,这段路树荫茂密,看不到远方,我听别人说是连续两公里上坡,还以为没到。除了左小腿,右小腿和左大腿都有过要抽筋感觉,过医疗站必去喷一下。过了35km 大补给站,看到一眼到头都是上坡的大直路,但反倒跑起来不那么辛苦,小步的跑虽然慢但不是非常吃劲,没有撑不住要停下来走的感觉。过了37km 看到前面到顶了,才走了最后一段。

38km 后急下坡,虽然轻松但脚肌肉已经太疲累跑不起来,6分步速。而且,左小腿抽筋感很强,膝关节和髋关节都劳累,右膝特别不适。虽然是最后几公里,但真有点崩溃的感觉了。40km 前后应该是感觉最差的一段。

41km最后一个拐弯后,又开始上坡,这时咬牙也得坚持了,要抽筋也不管了,左四头肌和小腿的肌肉都在不断的抽搐着,其实它们还是有继续工作的能力的。但,怎么还看不到终点啊?终于在过42km牌子后看到终点拱门……这两百米也不短……

冲线后除了挂上奖牌,组委会还很贴心的准备了披风给披上,真温暖。从马路下去会场有好多级台阶,也专设了一个斜坡供大家下去。虽然是斜坡,我都只能慢慢蹭下去,膝关节累得弯不了了,志愿者马上过了扶我到医疗点喷药。傍晚大巴回到广州,下车后走路都一拐一拐,右膝的旧患,在弯曲时痛,不能受力,特别是下不了楼梯。休息一晚后,感觉好很多。

这次跑的心率一直很平稳,起跑几公里没有一下子飙升,十公里后一直维持在160以内,从头到尾都没有特别气喘吁吁的,没有那种肌肉糖原消耗尽突然有氧功能跟不上的感觉。早餐吃了三碗粥,一个鸡蛋,几个红薯,一瓶运动饮料直到起跑前喝完。跟往常一样,水站不喝水,饮料站都喝一些饮料。18km 能量胶,25km 半根香蕉,30km 左右能量胶,35km 半根香蕉,觉得能量补充足够了。带来3个能量胶剩了一个,补给站也没有多拿食物,感觉不需要。

但是,依然困扰的是小腿后侧肌肉抽筋的问题,上次盐田半马在最后一公里也出现了。广马前的训练几次三十多公里没有出现过。广马天气热太阳晒,这次气温很适宜,还吃了盐丸,还是出现。应该问题还是训练得少,肌肉不能坚持长时间运动。

Trouble Shooting: Windows响应缓慢

| SysAdmin, Windows

最近一个星期,电脑出现了缓慢的现象:打开任何应用,窗口都要等待上一段时间才能出现。

Process Explorer 中看到进程已经出现,也没有什么CPU占用,但窗口就是不出来,好像是要等到什么操作超时。这里如果能够查看调用栈,应该就能知道程序卡在什么地方。

上网搜索一下,看到一些文章提到 troubleshoot Windows 问题,都用到了 WinDbg 来分析进程调用栈。这篇文章简要介绍了 WinDbg 的使用方法(不过可能文章年代过于久远,有些细节已经对不上了)。于是安装相应软件,实操一下。

只是用到 WinDbg 的一些皮毛功能,包括这些命令:

Command Description
~ 列出所有线程
k 5 显示当前线程的stack trace,如果附带数字则限制打印条数
kb 显示stack trace,包含前三个调用参数
~n[cmd] 对n号线程执行 cmd 操作
~*[cmd] 对所有线程执行操作,如 ~*k 5
~ns 切换到n号线程

WinDbg 可以 attach 到一个执行中的进程。但我只是想看看某个时刻那个进程在干什么,用 Process Explorer 创建进程的 minidump 更加简单,在 GUI 中选择进程,右键菜单选择 dump 就能创建出 dump 文件,可以多 dump 几次,然后用WinDbg 打开 dump 文件查看。

Loading Dump File [C:\tmp\2014-12\notepad++.dmp]
User Mini Dump File: Only registers, stack and portions of memory are available

Symbol search path is: srv*c:\LocalSymbols* http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 7 Version 7601 (Service Pack 1) MP (4 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Tue Dec 30 15:53:27.000 2014 (UTC + 8:00)
System Uptime: not available
Process Uptime: 0 days 0:00:06.000

这是 notepad++ 启动6秒钟后的 dump,看看这时有些什么线程,分别在干什么:

0:000> ~*k 6

.  0  Id: 1894.d54 Suspend: 0 Teb: 7efdd000 Unfrozen
ChildEBP RetAddr 
00137980 74c314ab ntdll!NtWaitForSingleObject+0x15
001379ec 764b1194 KERNELBASE!WaitForSingleObjectEx+0x98
00137a04 764b1148 kernel32!WaitForSingleObjectExImplementation+0x75
00137a18 74a5098c kernel32!WaitForSingleObject+0x12
00137a28 74a4fcdc msctf!CCicEvent::Wait+0x15
00137ca4 74a4fbd9 msctf!CAssemblyList::LoadFromCache+0x94

   1  Id: 1894.107c Suspend: 0 Teb: 7efda000 Unfrozen
ChildEBP RetAddr 
WARNING: Frame IP not in any known module. Following frames may be wrong.
00b4ff88 764b338a 0x1e02d1
00b4ff94 76ecbf32 kernel32!BaseThreadInitThunk+0xe
00b4ffd4 76ecbf05 ntdll!__RtlUserThreadStart+0x70
00b4ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

   2  Id: 1894.4bc Suspend: 0 Teb: 7efd7000 Unfrozen
ChildEBP RetAddr 
02ecfe28 76ee1ad0 ntdll!NtWaitForWorkViaWorkerFactory+0x12
02ecff88 764b338a ntdll!TppWorkerThread+0x216
02ecff94 76ecbf32 kernel32!BaseThreadInitThunk+0xe
02ecffd4 76ecbf05 ntdll!__RtlUserThreadStart+0x70
02ecffec 00000000 ntdll!_RtlUserThreadStart+0x1b

   3  Id: 1894.f30 Suspend: 0 Teb: 7ef9f000 Unfrozen
ChildEBP RetAddr 
033afe28 76ee1ad0 ntdll!NtWaitForWorkViaWorkerFactory+0x12
033aff88 764b338a ntdll!TppWorkerThread+0x216
033aff94 76ecbf32 kernel32!BaseThreadInitThunk+0xe
033affd4 76ecbf05 ntdll!__RtlUserThreadStart+0x70
033affec 00000000 ntdll!_RtlUserThreadStart+0x1b

   4  Id: 1894.2034 Suspend: 0 Teb: 7ef9c000 Unfrozen
ChildEBP RetAddr 
04d1fdf4 76ecc6c5 ntdll!NtWaitForMultipleObjects+0x15
04d1ff88 764b338a ntdll!TppWaiterpThread+0x33d
04d1ff94 76ecbf32 kernel32!BaseThreadInitThunk+0xe
04d1ffd4 76ecbf05 ntdll!__RtlUserThreadStart+0x70
04d1ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

共有5个线程,只有0号线程在干活。看0号线程的完整调用栈:

0:000> k
ChildEBP RetAddr 
00137980 74c314ab ntdll!NtWaitForSingleObject+0x15
001379ec 764b1194 KERNELBASE!WaitForSingleObjectEx+0x98
00137a04 764b1148 kernel32!WaitForSingleObjectExImplementation+0x75
00137a18 74a5098c kernel32!WaitForSingleObject+0x12
00137a28 74a4fcdc msctf!CCicEvent::Wait+0x15
00137ca4 74a4fbd9 msctf!CAssemblyList::LoadFromCache+0x94
00137cd0 74a4e045 msctf!CAssemblyList::Load+0x39
00137d00 74a4e863 msctf!EnsureAssemblyList+0xe9
00137d28 74a4e30a msctf!CLangBarItemMgr::GetCurrentCategoryList+0x14
00137d44 74a4e67d msctf!CLangBarItemMgr::_Init+0xea
00137d58 74a7d0c4 msctf!CLangBarItemMgr::CreateInstance+0xea
00137d78 74a57f99 msctf!CLangBarItemMgr_Ole::CreateInstance+0x6e
00137d8c 76038ca6 msctf!CClassFactory::CreateInstance+0x14
00137e14 76053170 ole32!CServerContextActivator::CreateInstance+0x172 [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 1000]
00137e54 76038dca ole32!ActivationPropertiesIn::DelegateCreateInstance+0x108 [d:\w7rtm\com\ole32\actprops\actprops.cxx @ 1917]
00137ea8 76038d3f ole32!CApartmentActivator::CreateInstance+0x112 [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 2268]
00137ec8 76038ac2 ole32!CProcessActivator::CCICallback+0x6d [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 1737]
00137ee8 76038a73 ole32!CProcessActivator::AttemptActivation+0x2c [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 1630]
00137f24 76038e2d ole32!CProcessActivator::ActivateByContext+0x4f [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 1487]
00137f4c 76053170 ole32!CProcessActivator::CreateInstance+0x49 [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 1377]
00137f8c 76052ef4 ole32!ActivationPropertiesIn::DelegateCreateInstance+0x108 [d:\w7rtm\com\ole32\actprops\actprops.cxx @ 1917]
001381ec 76053170 ole32!CClientContextActivator::CreateInstance+0xb0 [d:\w7rtm\com\ole32\com\objact\actvator.cxx @ 685]
0013822c 76053098 ole32!ActivationPropertiesIn::DelegateCreateInstance+0x108 [d:\w7rtm\com\ole32\actprops\actprops.cxx @ 1917]
001389fc 76059e25 ole32!ICoCreateInstanceEx+0x404 [d:\w7rtm\com\ole32\com\objact\objact.cxx @ 1334]
00138a5c 76059d86 ole32!CComActivator::DoCreateInstance+0xd9 [d:\w7rtm\com\ole32\com\objact\immact.hxx @ 343]
00138a80 76059d3f ole32!CoCreateInstanceEx+0x38 [d:\w7rtm\com\ole32\com\objact\actapi.cxx @ 157]
Unable to load image C:\Windows\System32\kunlun.ime, Win32 error 0n2
*** WARNING: Unable to verify timestamp for kunlun.ime
*** ERROR: Module load completed but symbols could not be loaded for kunlun.ime
00138ab0 71a86801 ole32!CoCreateInstance+0x37 [d:\w7rtm\com\ole32\com\objact\actapi.cxx @ 110]
WARNING: Stack unwind information not available. Following frames may be wrong.
00138ad4 71a86722 kunlun+0xf6801
00138b0c 71a8648c kunlun+0xf6722
00138bf0 71a4fb9e kunlun+0xf648c
00138c58 71a51e63 kunlun+0xbfb9e
00138c8c 71a51efc kunlun+0xc1e63
00138cc4 71a51b90 kunlun+0xc1efc
00138d34 71a4fc81 kunlun+0xc1b90
00138d74 762d459a kunlun+0xbfc81
00138d90 762d2900 imm32!CreateInputContext+0x195
00138db8 762d1e8c imm32!InternalImmLockIMC+0xca
00138dc8 762d34ae imm32!ImmLockIMC+0xf
00138dec 750cd9e7 imm32!ImmSetActiveContext+0x62
00138e08 750cadf9 user32!FocusSetIMCContext+0x28
0013905c 750c75b7 user32!ImeSystemHandler+0x31f
00139084 750c75ed user32!ImeWndProcWorker+0x2c9
001390a4 750c62fa user32!ImeWndProcW+0x29
001390d0 750c6d3a user32!InternalCallWinProc+0x23
00139148 750c6de8 user32!UserCallWinProcCheckWow+0x109
001391a4 750c6e44 user32!DispatchClientMessage+0xe0
001391e0 76ea010a user32!__fnDWORD+0x2b
001391f4 00fe7ae0 ntdll!KiUserCallbackDispatcher+0x2e
001392d8 750f10d3 0xfe7ae0
001392fc 750f1125 user32!CreateDialogIndirectParamAorW+0x33
*** ERROR: Module load completed but symbols could not be loaded for notepad++.exe
00139328 00516a73 user32!CreateDialogParamW+0x49
0013934c 750caa3c notepad__+0x116a73
00139400 750c8a5c user32!_CreateWindowEx+0x210
0013943c 0041ee1c user32!CreateWindowExW+0x33
0013a7cc 00584fd4 notepad__+0x1ee1c
0013a7e4 00584fa0 notepad__+0x184fd4
0013a7e8 00400000 notepad__+0x184fa0
0013a7ec 00040d60 notepad__
0013a7f0 00110d3c 0x40d60
0013a7f4 00000000 0x110d3c

最后的操作在msctf中等待某个事件,msctf 是 Microsoft Text Service;回溯调用栈,看见imm32(Input Method Manager)相关的调用,看来这个无响应的现象与输入法有关系。而 stack 中出现的 kunlun.ime 是必应输入法。

试试把正在使用的必应输入法卸载后重启,系统就正常了。重新安装必应输入法,重启后系统又出现无响应现象。

但比应输入法已经使用了一段时间了,为什么开始没有出现问题呢?回忆了一下,大概是在安装了 Synergy 之后出现的,Synergy共享鼠标键盘,也许有可能与输入法产生冲突。尝试一下,卸载synergy后,即使安装必应,系统也正常。看来可以确认是两者冲突,试了 Synergy 1.4.16/17/18 几个64bit版本都不能与 Bing IME 1.6.98.04 工作。

Ok,对我来说问题解决了,进一步的不再深究。这次学会了使用 WinDbg 查看调用栈的简单操作。