赵翔鹏的Blog Xiangpeng's Thinkpad

2三/102

重新开张

之前的博客服务商yo2.cn不幸被和谐了,只好再花了点银子搬家。这次用的是国内的虚拟主机,应该没那么容易挂吧……

文字内容都已经恢复,不过大部分图片就丢了。url全都变了,所以搜索引擎暂时是搜不到这里来了。

先发这篇测试一下RSS是否能正常工作。

12十一/093

Windows里跟performance相关的一些概念

1、kernel里的Cache Manager

提供了在ReadFile、WriteFile时的cache,包括read-ahead和write-behind机制。原理是把application本来应该让file system服务的I/O request截走,转给cache manager自己拥有的一小块memory。

Cache manager就像一个应用程序,它只管虚拟内存,真正的物理内存管理都由memory manager做。所以cache那一部分memory也可能被page out。

只针对普通的file,dll、exe文件不会read-ahead。更精确的说,凡是用memory-mapped file方式读取的文件,都不会被read-ahead。

2、Prefetch:

在启动一个Process时,总要load一些dll,常用的几个icon等。如果等用到了再去读就比较慢,而且硬盘磁头会来回跑路。prefetch会根据上次process运行的历史记录,按照它们在磁盘上的顺序预读这些dll。

因此,一个程序第一次运行时可能硬盘要转很久,但以后再运行就快了。Prefetch对Boot也有类似的优化,会自动defrag启动时用到的文件。

可能的问题:上次打开的文件这次未必用到。

3、SuperFetch

为了解决“after-lunch effect”引入的。为啥午饭回来之后outlook很迟钝,硬盘在狂转?因为在idle的时候杀毒软件开始扫描磁盘,占用大量物理内存,outlook不幸被page out了。等杀毒软件运行完释放了内存,LRU算法会把杀毒软件留在内存的standby list里,而outlook的页面却不会从pagefile里回来。

类似Prefetch,SuperFetch记录内存的历史使用情况。它考虑了时间信息,比如“每天下午2:00要用Outlook”,这样就预先把需要的东西读到内存里。而且也会考虑把常用/重要的东西(比如输密码解锁那段code)尽量留在内存里。

只要发现你的空闲内存比较大(比如刚有一个大程序退出),它就会一点一点地吃掉你的空闲内存,把它认为需要用的东西放在内存里。所以很多人误以为SuperFetch浪费内存。

4、ReadyBoost:

用优盘当虚拟内存。hard fault发生时,从优盘读比硬盘稍微能快一点点。

5、ReadyBoot:

在boot的时候,预读一些硬盘数据到内存里。这个跟prefetch很像但是更智能。我现在还不是很清楚这个东西怎么工作的。还需要翻一翻宝书Windows Internals 5。。。

Update: 今天翻了宝书,发现宝书上只用了1页描述ReadyBoot……郁闷,还是不清楚。这也意味着即使我通过别的方法把它搞清楚,也不能把结果贴出来了。

18十/092

Sleepless in Seattle

上午睡到12:00,下午和晚上去逛了Seattle downtwon,于是回来就睡不着,郁闷中。。。写写游记,希望能早点困。

时间有限,去的地方不多。华盛顿大学是个不错的景区。要知道美国的“大城市”跟中国的城市一样也是千篇一律,无非就那么同样的几家品牌店,一个个数字编码的street和avenue。所以呢,华大的“古”建筑看起来有内涵多了。在被雨水浸湿的宽阔广场上,除了镶嵌彩色玻璃、带有尖顶和拱门的欧式建筑,有野鸭散步其间的草坪,鲜红的爬墙虎,在地上映出长长倒影的诡异砖墙高塔,还有若干跟我们一样不打伞的各色美女帅哥——btw,真正的西雅图人是不打伞的。向海边的方向望去,华盛顿铜像在大团氤氲的云雾中显得有点孤单。几棵很有些年头的樱花树散布在落叶缤纷的草坪上;虽然樱花是肯定见不着的,但也让我们这些东方人感到一点点的亲切。

雨下了又停,停了又下。这里的天气预报不好做啊!开车5分钟后从小雨变成大雨,再开5分钟又从大雨瞬间转晴天。继续走吧。

跟旧金山一样,这里有25-30度左右的恐怖斜坡,一直从山上通到海边。上到一个小山顶后,可以看得很远。市中心就那么一小片高楼,哪个都跑不出视野。Space needle,西雅图的标志建筑很不幸的早就不是最高建筑,不过等夜晚塔上亮起纯白的灯光后,看起来很美,好像一个巨大卧室里的一盏精致落地灯……反正我挺喜欢就是了。

到海岸边(有车就是好啊!),1st avenue上有些有趣的地方,比如第一家星巴克,flying fish market之类的,到处都人满为患。我必须承认,虽然被提醒过,flying fish还是比我想像的更囧……真正happy的还是crab pot餐馆,虽然等了45分钟才有位子(哈,当然不会傻到坐在门口等了,顺便就逛了逛附近的老城区,在黑乎乎的灯光下见到黑人兄弟若干,晃来晃去似乎很拽的样子)。

继续说crab pot!海鲜吃到饱不说,关键是吃的方法。没有碗也没有盘,一大堆螃蟹、虾、clam,mussel、香肠、煮土豆和嫩玉米被直接倒在垫了张大纸的桌上,然后每人拿木槌在小木板上狂敲一通~这比文明人的吃法有特别的趣味,超爽的……嗯,破坏一下吃饭的气氛,我忍不住想,每个木板上,都有多少个关节被敲碎呢……真相请看图

饭后去朋友家里小坐,11:00回来。Acknowledge一下热情的朋友,要是自己瞎摸,怎能玩得high到现在都睡不着啊~:)

http://picasaweb.google.com/zhao.xiangpeng/Seattle

分类: 心情 2 评论
12十/090

几个马路上常见的单词

yield,让路。to slow down or stop in order to let another vehicle pass。一般在并线的地方出现。

多线程编程里面会用到yield,是线程主动让出CPU,让下一个线程执行。

detour,绕行。

微软研究院有个项目叫detours,是用来hack Windows API的。系统本来要调用Windows API的code,现在却要转到我自定义的代码上。很贴切。

顺便感叹一下,老美是先学了这些词再去理解计算机的术语,咱们正好反过来。

LOW SHOULDER ,道路两旁低。类似的还有soft shoulder。

limosine,豪华轿车。在租车的地方看到的标志。

ped xing,这个很容易猜到……pedestrian crossing.

11十/091

back to USA

又一个秋天,重逢的是蓝天白云,碧海绿树的美丽景色。

跟上次来美国的独自折腾相比,这次条件好得太多。不用转机,11个小时就到。旅店、租车都由公司预先搞定。有人同行不担心找不到路,去超市买东西也不再担心东西太多自行车载不动了。

以前不开车也没在意,到停车场一瞧,好像所有的车都比中国的大一圈。我们租的是辆凯美瑞,感觉比国内的凯美瑞就大一些。更不用说各种夸张的SUV了,国内的SUV真的只能算mini-SUV。

明天还可以休息一天,去downtown逛一下,后天去上班啦~

分类: 心情 1个评论
15八/091

为什么坚持写博客的人很少

为什么我很久不写blog了?一个原因是觉得自己在OS,Performance这个领域懂得太少太少,自己看来很新奇的东西其实都是些基础知识。不过现在想想懂得少又如何?就算粗浅的见解不能让读者感兴趣,至少还可以督促自己的学习。

工作很忙是一个原因,但决不是关键的原因。虽然每日的工作时间比在学校里多了,但玩的时间并没减少多少……写到这里我想我应该少花时间打台球……当然最近也有点打够了……-_-

还有,之前在某同学blog看到的一帖,让我很感叹。博客没人看的时候,作者会希望有更多人看。等看的人多了,写东西的心情就不一样了,反而难下笔了。说得太对了。所以要做好博客的定位。心情帖就灌到xiaonei,msn签名这种地方好了。(话说twitter不就相当于把msn签名收集起来放在网页上再允许留言吗……)

最后,坚持做任何一件事都很难。(比如每天按时睡觉就很难 :P )所以才叫坚持。好在朋友的一个提醒,一个鼓励,都会给人很多动力。谢谢提醒我应该继续写博客的朋友们。:)

分类: 心情 1个评论
15八/091

由无数细节组成的系统

计算机科学总是讲abstraction。这是源自数学的思维。formal methods可以说把这个发挥到了极致。但实际系统并不是这样。不要说构建Windows这样的庞然大物,就只是要写一个实用的小软件,就会遇到无数的细节。performance,security,scalability,debugging……除了functionality之外,有无数的事情要考虑。

传统的formal methods注重functionality也没错,因为在某些情形下(比如算法领域)functionality的正确性已经够难了。但这却不是软件工程中的主要问题。

我们能做的,就是尽量挣扎着把细节包装起来。比如,工程师做出一个个框架,分出若干个层次。框架可以帮助我们,但框架并不能解决一切问题,因为好的程序员必须了解各种细节。最近读一个基于ATL/WTL的真正的product code,发现这一年来看的n本书都没白看。比如,不懂C++内存布局,不懂各种calling convention,compiler的差异,就不能理解COM的设计(btw,强烈推荐《COM本质论》的第一章)。

researcher也自有办法。因为很多细节是正交的。在TASE'09上听到Zhong Shao做的invited talk,分不同的aspect去验证汇编代码的不同性质,这个是正确的思路,而且我觉得可以做更多的东西出来。以前做business process的security验证,这个也可以归到这个思路,不过high level的东西比较虚,做起来虽然不难但并不容易很深入。而Shao对汇编和机器本身建模,比如对interrupt handling建模,这个就很有新意,且竞争者较少——很多数学系出身做formal methods的人,都不太懂系统底层。

是的,跟C++和汇编相比,写Java很容易。不过事情一旦很容易,于工业上看,就不值钱了;于学术上看,就没啥好研究的了。所以,重视各种细节吧。

27二/095

品味红酒

话说偶今天小资了一把,在公司尝试了各种红酒,从Sauvignon Blanc,Chardonnay,到Cabernet Sauvignon,Shiraz……最后是 Bordeaux的Margaux,好酒很香绵,只可惜没有美食相配。喝到微醺就下班了。快乐的星期五~

红酒的红色来自葡萄的皮。在制作之初葡萄皮就与果肉分离,在发酵的过程中添加一段时间又要取出。复杂吧。白葡萄酒为什么是白色?因为没有加葡萄皮。

制作一瓶好酒,要天时地利人和。先说天时,不同年份的酒特性相差很多,据说2005年的法国红酒就可以长期存放,而之前00-04年的酒都不太适合放太久。再说地利,法国地图上一小块地方就有无数的酒庄无数的葡萄品种,极品产地的酒可以卖到>6w人民币一瓶,极品产地的极品酒庄的极品酒就更不用说了。最后,采摘葡萄的时机和酿酒师的技术都很重要。

品酒师说100块以内的红酒就不要买……我承认我很土,虽然国产赤霞珠很烂,但总算买得起……btw,据说双井的家乐福周末经常有免费品酒活动,可以去蹭,都是进口的好酒噢。

说到国产红酒,原来赤霞珠和解百纳是同一种葡萄Cabernet Sauvignon (号称超级容易养)。如今被当作两种,完全是中国人的发明。

p.s. 品酒师是偶们公司的一位architect,太有才了;再顺便说一下今天尝的酒都是他自掏腰包带来的,太葱白了~

最后提个思考题:做葡萄酒的葡萄一般是什么味的?

21二/095

C#和CLR的15个细节

这两周一直在training,一共听了4个课程,相当的累啊。

今天先把Jeffrey Richter的培训课:C# and CLR中讲到的一些东西整理一下:

  1. foreach的性能问题

    foreach(string s in rows) { foo(s); }的实现是:

  2. IEnumerator e = rows.GetEnumerator();
    try {
      string s;
      while (e.MoveNext()) {
        s = (String) e.Current;
        foo(s);
      }
    }
    finally {
      IDisposable d = e as IDisposable;
      if (d != null) d.Dispose();
    }

    每一步都调用了e.MoveNext()和e.Current两个方法;而大多数时候,完全有可能优化为一次调用。显然这对性能是有影响的。虽然foreach对于数组作了单独的优化(编译成for循环),但这还是值得注意的。

    那么,怎么做比较快?

    对于List等Collection,可以用ForEach(Action<T> action),FindAll(Predicate<T> match),ConvertAll<U>(Converter<T, U> converter)等方法。它们比较快,但不是所有实现IEnumerable的类都提供。

    LINQ追求compatiblity,而不是performance。因此LINQ的实现完全采用了foreach。值得注意。

  1. yield的实现原理

    实现一个支持IEnumerable的对象时,一般会用到yield关键字,这样foreach遍历这个对象时,可以做到lazy evaluation。例如:

    class MyCollection: IEnumerable<char> {
      private string s; ...
      public IEnumerable<char> GetEnumerator() {
        for (int i=0; i<s.Length; i++) {
          yield return s[i];
        }
      }
    }

    执行到yield时函数返回,下次调用时,接着上次运行的位置继续运行。这个continuation的效果是怎么做的呢?

    包含yield的函数都会被编译器做成一个状态机。每调一次,就接着上次的状态继续运行。简单有效啊。我一直以为要有什么特殊的办法呢。

  2. exception handling的实现决定了throw的performance较差。

    可以用Int32.TryParse代替try{Int32.Parse…}catch{…},稍快一点。类似地建议使用Dictionary.TryGetValue。

  3. .Net CLR执行引擎对应于MSCorWks.dll和MSCorEE.dll这两个文件。

  4. .Net 3.0, 3.5没有对CLR作任何修改。

    所有增加的东西(比如LINQ)都是syntactic sugar,只改了C#编译器而已。

  5. AppDomain

    如果把.Net虚拟机看成一个虚拟操作系统,AppDomain的概念则类似于操作系统中的进程。

    可以用代码创建一个AppDomain,然后动态加载/卸载assembly,还可以设置权限,相当于提供了一个沙箱。

    跨AppDomain的调用类似于RPC。

    调用某个AppDomain内部的obj.foo(x)时,.net会自动帮你做出一个proxy object,你所调用的obj其实是一个proxy object。传给foo的参数x会先被被marshal,以保证AppDomain被安全隔离。

    谁用AppDomain?SQL Server用这个技术实现managed存储过程。IIS会把不同的Web Application放在不同的AppDomain里,以实现动态装卸。

  6. 动态载入Assembly的陷阱

    Sytem.Reflection.Assembly.LoadFrom(pathName)并不会载入pathName所指定的dll,而是看看pathName那个dll的名字、版本,然后到系统默认位置去找。(陷阱啊)

  7. C#里用reflection创建一个新对象

    用Activator.CreateInstance。(奇怪的名字啊。)

  8. C#泛型之“where”

    可以用“where”来限定T的接口。例如

    static T min<T>(T arg1, T arg2) where T: IComparable<T> {…}

    不写where的话,就不能调arg1.CompareTo(arg2)。

    为啥不把T换成IComparable?一是为保证arg1, arg2一定是同一个类型,二是泛型的效率更高。(JIT会为不同类型的T各生成一份native code,从而避免了boxing)

    更多where的细节:

    * 要想调T t1 = new T(),必须声明where T: new()或者where T: struct

    * 要写T t2 = null,必须声明where T: class

    * T z = default(T)是一个特殊的用法,会把T的每个bit都置为0。

    * 假设定义了Foo<T>(T x, T y),则if (x==null) … 是可以通过的,虽然C#中value type的值不允许为null(例如int a=null是错的)。这是因为,此时的语义是一致的,反正if里面的操作不被执行就是了,所以编译器对这种特殊情况网开一面。

    * if (x==y)不行,除非写了where T: baseclass。(这里我也没理解为啥。。。>_<好像说是不知道应该用reference比较还是value比较?)

  9. 匿名函数的背后。。。

    在C# 2.0以后可以用匿名的delegate,如ThreadPool.QueueWorkItem(delegate (Object obj) { Console.WriteLine(obj); })

    但编译器的实现会带来一点点overhead,会生成一个小小的静态WaitCallback对象,可以用Reflector看生成的代码。(不要打开Reflector的optimization,否则就看不到了)

    如果是自己写的话,可以选择每次动态建立一个WaitCallback对象然后销毁。当然这样做性能可能差一些,但这里的idea是:编译器会自动做一些事,但不一定是你所希望的。在使用这些高级feature前,最好先搞清楚背后发生了什么。

    另一个细节:如果匿名函数中使用了外层函数的局部变量(即所谓的function closure),会导致创建额外的shared-state object,把用到的局部变量做成一个新对象传给匿名函数。

    上述描述同样适用于lambda函数。因为C#的lambda函数就是匿名函数,改了改语法而已。

  10. Nullable type

    虽然C#要求value type的值不能是null,但写数据库程序时经常遇到某个值是null的情况。为此,C#2.0引入了Nullable type。例如,int? x = null。

    int? x其实就是一个缩写,等价于Nullable<int> x。Nullable是预定义的一个类,简单地对x作了封装。(因为增加了一个类,显然对性能稍微有点影响)

    这个小改动的实现其实很麻烦,需要修改CLR。为什么?因为原先的x是一个value type,现在则变成了一个object,看这个:

    void M(Object o) {
      if (o=null) {Bar();}
    }
    void F() {
      int? x = null;
      M(x);
    }

    如果CLR不专门做修正的话,上面的Bar()不会被执行。(思考题:想一想为什么~)

    另外,C#还引入了一个默认值运算符“??”,称为null-coalescing operator。

    一句话,x ?? value是 (x==null) ? value: x的简写。

  11. 属性(property)的简单声明

    public int x {get; private set;}是个很好用的句式。

    注意,public int x {get;}是错误的,不能通过编译。

  12. Extension method

    static class MyExtMethods {
      static public GetFirstLetter(this string s) {return s[0];}
    }

    然后就可以用string s = “hello”; char ch = s.GetFirstLetter()了。

    原理很简单,编译器把上面那句话翻译成MyExtMethods.GetFirstLetter(s)。LINQ就用到了这个技术。

  13. 匿名类型的背后。。。

    var o = new {name = “Xiangpeng”, id = 123 };

    在这背后是编译器生成的一个匿名类,包含了两个只读属性,形如public int id { get {return _id;} }为什么不做成可读写的呢?

    很微妙。匿名类自动生成了GetHashCode(),返回的是对所有属性的hash code做XOR的结果。如果允许修改属性值,那么Hash code的值就会变化;而这个可能会出问题~保险起见,只读吧。

  14. 每个thread占1M物理内存

    在Win32编程中thread的1M stack空间是Reserve的,直到真正用时才占用物理内存;而在.net中,这1M空间直接被commit。

    还好,可以在新建thread时指定stack size。不过这也比较危险,设小了怕不够。实际上,最好尽量避免创建thread——太多的thread要么导致CPU竞争和context switch,要么都block着浪费内存。建议是:能用ThreadPool就用ThreadPool。

累死了,写了这么多……Jeffrey还有一个更牛的课:.net threading。里面的东西更多……要不要再总结一下呢。。。Thinking

分类: C# 5 评论
12二/090

时间管理啊……

为什么在长假和坐飞机的时候,能够快速地阅读生涩著作呢?长假,是彻底清空,有了接受新信息的空间,有了闲暇的时间。坐飞机或在机场,创造出一种深度阅读的“狭小空间”。但这种解读还是表象,或许这两者的真正共性是,它让我们离开了庞杂的信息,离开了哪些摆在四周的阅读糖果零食,我们都知道,糖果吃起来不错,但吃多了很难受,只吃糖果会更加不舒服。

这段话说的太好了。但为什么我就没有办法把主动网络断掉慢慢研究WRK呢。。。

   下一页