Archive for the ‘雕虫技’ Category

听说python在CPU核心多的时候速度反而慢

从这儿看到的
A GIL Adventure (with a happy ending)

写了个测试, 的确是, 环境是python2.6.5 x86, Win7, 双核

D:\works\stars\server\utils>pbench.py
4.767000 seconds for a 5 x 100000 multithread test
2.997000 seconds for a 5 x 100000 single thread test
multithread overhead: 59.059059%
set process affinity // 把进程绑到一个核心上
3.755000 seconds for a 5 x 100000 multithread test
2.909000 seconds for a 5 x 100000 single thread test
multithread overhead: 29.082166%

D:\works\stars\server\utils>pbench.py
4.699000 seconds for a 5 x 100000 multithread test
2.914000 seconds for a 5 x 100000 single thread test
multithread overhead: 61.256000%
set process affinity
3.910000 seconds for a 5 x 100000 multithread test
3.004000 seconds for a 5 x 100000 single thread test
multithread overhead: 30.159774%

Linux下更可观, 环境是python2.6.6 x64, CentOS, 双路x四核

[xxx@xxx test]# ./dist/pbench
6.152628 seconds for a 5 x 100000 multithread test
4.913056 seconds for a 5 x 100000 single thread test
multithread overhead: 25.230169%
set process affinity to 1
5.032502 seconds for a 5 x 100000 multithread test
4.931799 seconds for a 5 x 100000 single thread test
multithread overhead: 2.041912%

[xxx@xxx test]# ./dist/pbench
6.162305 seconds for a 5 x 100000 multithread test
4.903964 seconds for a 5 x 100000 single thread test
multithread overhead: 25.659672%
set process affinity to 6
5.070047 seconds for a 5 x 100000 multithread test
5.042279 seconds for a 5 x 100000 single thread test
multithread overhead: 0.550706%

用了有一段时间Python, 遇到的第一个比较烦的问题, blocking raw_input

我有一个daemon程序, 运行中要求能接收用户输入命令退出, 也能超时退出

这两个事情都很简单, 前者:
daemon.start() # daemon在另一线程中运行
While True:
    cmd = raw_input()
    if cmd == ‘exit’:
        break
daemon.stop()

后者更简单了
daemon.start()
sleep(10)
daemon.stop

两个一起做
daemon.start()
While True:
    cmd = raw_input(1) # 检测一秒的input, 到时就退出
    if datetime.now() > exit_time:
        break
    elif cmd == ‘exit’:
        break
daemon.stop()

可是问题来了, raw_input不支持timeout, 它只能一直等到用户有输入为止, 彻底的blocking操作

搜索了一下发现不少人有这个困扰, 比如这个:
http://www.gossamer-threads.com/lists/python/dev/791714
在*nix下很简单, 用select等到stdin有输入为止, 而select是可以timeout的, 可是Windows下的select只能在socket上工作, stdin不行

类似的还有个用signal的解决方法, 不过兼容性就更差了

这里有个办法在Windows上调用msvcrt来实现non blocking input
http://bytes.com/topic/python/answers/46473-non-blocking-raw_input
可是看起来就很丑…

换条路, 分两个线程做, 一个线程里面sleep等超时, 另一个线程里面raw_input, 超时了就把raw_input线程杀掉, 可是python里面不能随便杀掉线程…

后来因为时间紧迫, 用了一个很丑的方案: 超时之后, 用ctypes直接调用TerminateProcess结束进程, 也就杀死了raw_input, 反正当时只在Windows下运行

可是最近要移植Linux, TerminateProcess肯定是不能用了, 试了一下用sys.exit()退不掉, 试验了一下是因为我在主线程里raw_input, 另一线程里超时sys.exit(), 这在Windows下ok, 在Linux下sys.exit()只会退掉超时那个线程, 影响不到主线程, 如果反过来在另一线程里raw_input, 在主线程里超时sys.exit(), Linux下就能正常结束掉

总之是要改, 还是想改得不那么丑陋, 找来找去突然发现threading.Thread有一个daemon属性:
http://docs.python.org/library/threading.html#threading.Thread.daemon
The entire Python program exits when no alive non-daemon threads are left.
这话说得真够绕的…

这下清爽了, 不用任何平台相关的花招就可以搞定:
from time import sleep
from threading import Thread, Event

e = Event()

def read_loop():
        while True:
                print ‘type something:’,
                a = raw_input().strip()
                if a == ‘exit’:
                        e.set() # 设置Event让主线程退出
                        break
                else:
                        print ‘you typed:’ + a

t = Thread(target = read_loop)
t.daemon = True # 关键, 不设这个的话超时之后read_loop线程还在, 进程退不掉
t.start()

e.wait(10)

if e.is_set():
        print ‘you typed exit’
else:
        print ‘time out’

关于DNS设置的建议

国内ISP的DNS经常不稳定, 于是我经常都用OpenDNS, 后来又改用Google DNS, 但是访问国内某些网站会慢, 因为ISP CDN会失效

虽然dnsmasq可以手动设置对某些域名使用指定的DNS服务器, 但是一个个手动加似乎很烦, 而且不是很全面

在这儿看到个好主意, 按Alexa排名找出中国前100域名
http://code.google.com/p/autoddvpn/wiki/DNSMasq

这样基本就足够了

还有个小问题是我的路由器刷的是Tomato固件, 这个设置太长写不进去…
看了一下dnsmasq的man page, 有个conf-dir参数
于是启用tomato的jffs, ssh上去建立目录/jffs/dnsmasq.conf/, 所有配置都写到那里
然后在tomato的dnsmasq custom configuration里写上conf-dir=/jffs/dnsmasq.conf/搞定

Virtual Box真美

上次说的折腾OSX86, 折腾到一半就搁下了, 因为经常搞到BIOS设置混乱必须Clear BIOS才能启动, 折腾得很痛苦

退回使用虚拟机, 刚好发现VirtualBox竟然已经直接支持Mac OS X Guest了, 这下不用EFI模拟+各种Hack了, 真美

不过官方是说只在Mac OS X Host上才行, 看到这个心一凉

不过搜到一个Hack:
http://www.projectosx.com/forum/index.php?showtopic=1320

我用的是Virtual Box 3.2.8, firmware efi64这个设置不必要, 而且一旦在Virtual Box GUI里面修改其它设置, 这个选项会被置回EFI, 直接用OSX原盘启动安装, 升10.6.4, 一切顺利, 文中的声音的修复我也没弄, 直接在Virtual Box里Disable Audio了, 反正也不需要

从这个Hack来看, Virtual Box的EFI已经ok了, 但是VBoxInternal2/SmcDeviceKey这个特征串原本是在运行时从Host读取的, 如果不是用Mac OS X Host, 这个值就不能通过OSX的检测, 但是Virtual Box包含这个串估计会招来Apple的官司, 所以只好只在OSX Host上才支持, 这个方法Override掉这个串, 通过检测

真美

PS: 在我的CPU/内存基本跟X61相当的台机上Virtual Box里的OSX比X61上的OSX86还快, 也就是说X61的显卡还不敌Virtual Box的虚拟……

新折腾 – OSX86

因为买了ipad, 想折腾iphone os sdk, 可这玩意竟然只能在MacOSX上装, 为这买个Mac好像有点过份, 于是转向OSx86, 折腾了两个晚上, 写点笔记

先是下了个iDeneb 1.6, 觉得这种人家做好的盘应该会比较省事, 结果启动失败, 放弃

傻瓜教程很多, 但没一个满意的, 看起来毫无营养, 授人以鱼不若授人以渔这道理懂的人真不多, 找来找去只有这篇我觉得不错, 方法上很符合我的理念, 推荐, 至少可以先看看术语的部分

其实在大多数Intel CPU的机器上, Apple的官方内核就可以运行, 这种方式在坛子上被叫作Vanilla, 不需要第三方内核, 我刚好是Intel, 所以就不用折腾这个了

虽然内核可以, 但原盘是不能直接启动的, 硬件方面还是有些差异, 需要用第三方引导器来引导, 它会模拟EFI, 加载DSDT, 加载各种第三方驱动, 然后就可以在PC上引导OSX, 当然, 也能引导本身就是一个Mac OSX系统的Mac OSX安装盘. 引导器我用的是Chameleon, 据说AsereBLN更好, 不过那个站似乎挂了

Chameleon安装很简单, 如果你有MAC机器, 按Chameleon的说明档安装, 或者像我, 用grub4dos把chameleon的stage2当作kernel加载, 我把它装在一个U盘上, 启动的时候选优盘启动, 启动之后会出来图形菜单, 选Snow Leopard安装盘开始安装

没有光驱的话可以把Snow Leopard镜像写到U盘上, 我用了一个8G U盘, 分了一个1G的区, 里面放Chameleon和Extras, 剩下的再分个区放Snow Leopard安装盘, 因为只有两个分区, 也没多大, 用MBR分区就可以

不过直接启动基本上会kernel panic…

EFI模拟是自动的, 基本上不需要设置

DSDT很烦, 基本上需要手动来, 上面那个帖子有比较详细的说明, 不过太长了我还没看完

驱动要到处找, 基本上很麻烦…

DSDT/驱动都可能导致启动不了, 用verbose参数-v看kernel panic报错是什么导致的, 然后去Google搜索解决方法, 大致的办法是: 删除/禁用不兼容的官方驱动, DSDT修改, 加载第三方驱动, 需要耐心

搞定了启动Kernel Panic之后就进安装了, 还有几点值得一提的:

Snow Leopard只能用GPT分区表, GPT是个好东西, 但是微软系统不支持从BIOS引导GPT分区上的系统, 从EFI倒是可以, 但是Chameleon的EFI模拟不支持引导Windows, 好在Snow Leopard可以装到移动硬盘, 我把移动硬盘格成GPT, 问题解决. 但(据说)实际上装完后改成MBR(需要第三方工具)是没有问题的, 有一个Hack可以让Snow Leopard安装程序忽略这个检查直接装到MBR分区, 不过我没折腾这个. 另外注意Apple的GPT/MBR策略跟微软的不太一样, Apple操作GPT分区表时会生成对应的MBR, 微软只是生成一个Dummy MBR, 在MBR不是Dummy的时候, 它是MBR优先的, 它看到Apple生成的对应MBR的时候就会认为这是个MBR分区表, 如果你在两个系统上都进行分区表操作, 很容易造成混乱, 我的建议是用Apple操作分区, 然后用gptsync –e生成dummy mbr来make windows happy, 或者去用那个MBR Hack

出问题的时候还可以试试换换USB口, 也许有用, 我的本上三个USB竟然有一个不能用, 这个USB在BIOS/Win7/Chameleon下都OK, 但是一旦OSX内核加载, 这个USB就死掉了, 不管是U盘还是移动硬盘还是鼠标

最好弄俩机器, 一台折腾, 一台Google, 不然老是要重启进Window查东西下驱动什么的

总之, 太麻烦了, 太麻烦了, 破解的贤者们的确做了很多, 但是, 老实说我觉得还不够好, 比如为什么不能从ACPI DSDT表自动生成EFI DSDT呢? 为什么不能搞一个Repos放着所有驱动, 然后自动加载呢? 我还没折腾完, Trackpoint, wifi, 蓝牙, 都没搞定, 还得继续折腾…

最近做了一个相当复杂相当蛋疼的折腾

我有一个古早古早以前买的4G的SD卡, 外壳很脆, 后来它就变成了个裸板子, 因为没有外壳会无法碰到读卡器的有卡检测触点, 一般来说会被报没有卡, 一直放在一个被我焊死了检测触点的U盘样的SD读卡器里当U盘用
而且因为没有穿外套小了一圈, 经常会接触不良

可是丢掉好像有点可惜:(

前几天发现淘宝上还有卖U盘主控板的@_@ 买了一个, 把那个SD上的Flash芯片焊下来焊到那个上面去了

因为那个卡相当老, 用的Flash还是SLC的, 焊成U盘速度是30/25 -_,-

其实买一个也就百来块…

再其实我手艺不好, 是卖板子那个店主帮我焊的…

VMware NAT problem on Windows 7 host

昨天在本本的Win7上VMware里装个Debian想试个啥, 结果apt源配置那里死活过不去, 今天在公司Vista台机上装了个, 一切正常, 把装好的虚拟机镜像拷回来用, 果然也还是不能访问网络, ping能通但是连不上, wget/w3m都不行, 奇了怪了, 好在有Google, 搜到两篇文:

http://communities.vmware.com/thread/206553
已经有人反映到官方论坛, 但官方的意思是"Win7还没正式咱不支持."

http://blog.tiensivu.com/aaron/archives/1818-How-to-get-VMWare-Workstation-6.5-Guest-VM-NAT-working-with-a-Windows-7-Build-7000-host.html
这个帖子比较有意思而且解决了问题, 大意是用Windows自带的ICS代替VMware的不能正常工作的NAT服务.

其实他的步骤很累赘, 都用ICS了还费那劲设VMware的DHCP/NAT作甚, 直接在那儿把原来的两个没用的Adaptor删掉, 没用的DHCP/NAT服务关掉, 建个新的Adaptor, 把ICS设好, 把虚拟机的网卡设到这个新的上面, 搞定.

写下是当笔记, Win7是RC(build 7100), VMware是Workstation 6.5.2 (build 156735), 不知道啥时候能有官方解决方案呢.

神奇的Trim

前几天看到一篇文, 叫"漫谈Windows 7对固态硬盘的优化", 里面有这么一段:

"在Windows 7里,如果固态硬盘报告支持ATA协议数据集管理(DSM)命令里的Trim属性,NTFS文件系统就会在用户删除文件的时候要求ATA驱动向固态硬盘发出新的Trim操作指令,告诉它相关页面可以安全擦除。固态硬盘得到这一指示后,就不会急于执行擦除操作,而是等到合适的机会,也就是再次有写入操作的时候,因为这时相关页面已经可以重新使用,就不需要再执行擦除操作了。"

这也太神奇了吧, 难道Trim一把, 本来必须要先擦除才能写入的Flash现在就不用擦除了? 我等草民实在不能理解. 找原文来看看:

http://blogs.msdn.com/e7/archive/2009/05/05/support-and-q-a-for-solid-state-drives-and.aspx

"In Windows 7, if an SSD reports it supports the Trim attribute of the ATA protocol’s Data Set Management command, the NTFS file system will request the ATA driver to issue the new operation to the device when files are deleted and it is safe to erase the SSD pages backing the files. With this information, an SSD can plan to erase the relevant blocks opportunistically (and lazily) in the hope that subsequent writes will not require a blocking erase operation since erased pages are available for reuse."

这就能理解了, 比较准确的翻译应该是"SSD可以在恰当的时候(晚一点)再去擦除相关的块, 这样接下来的写操作可以不用等待擦除操作完成, 因为有(其它的, 译注)擦除过的块可供重用"

我不会翻译, 丑点但意思应该对, 原译者可能对文件系统, Flash(负载均衡)原理不太了解, 原文理解起来可能比较困难吧…

简单的说, 引入Trim之前, 文件系统对SSD来说是个黑盒, 整个文件系统所占用的空间对SSD来说都是被使用中, 文件系统中的未使用空间也被保持着, 这完全是浪费, Trim扮演的角色就是给文件系统到SSD提供了一个接口, 让SSD知道哪些块是文件系统未使用的, 这对提高负载均衡的性能非常有利.

复杂了说, 首先你要知道闪存的操作不像内存硬盘一样随便儿写1写0, 闪存的擦除(写1)操作是对块的, 而且慢到死, 其次你得知道闪存一定要有负载均衡, 为了寿命也为了性能, 而且用于负载均衡的冗余块越多越好(这很好证明, 举个极端的例子, 有一个冗余度是无穷的SSD, 这样只用写就行了, 永远不需要进行那个该死的擦除操作, 证毕, 不对, 好像还需要证明单调性…)

闪存卡/SSD出现以前的Flash应用常常是裸的一块NOR Flash接上来, 负载均衡都是在JFFS/TFFS这样的Flash文件系统级实现的, 所有文件系统空闲的空间都被用来做为负载均衡冗余, 根本就没有上面这种问题, 现在很多嵌入式系统的固化OS都还是这么做, 像手机什么的, 可是到了消费级产品, 闪存卡, SSD这些东西, 必须得使用FAT/NTFS这些通用文件系统, 像硬盘一样提供给OS一个平坦的块设备接口, 只能在这一层之下做负载均衡, 只能靠硬件上多加的冗余容量(你看Intel那个X25-E用40GiB的Flash颗粒做32GB的SSD), 有了Trim之后, 这个情况就改观了.

另外我觉得其实原文逻辑有点问题: 有Trim之前, 文件系统删除一个文件, SSD根本不会去擦除那个块, 哪敢啊, 还以为在用呢, 这时候就算有写入操作, 也不用等(根本就不存在的)擦除操作. Trim的好处应该是: 有Trim之后, SSD就知道那些块不被占用了, 有空闲(没有读写操作)的时候那些块就会被擦掉, 这样接下来的写操作就有更多擦除过的块(不仅仅是硬件冗余的那些)可供使用, 可以撑得住更久的密集写入而不用等待缓慢的阻塞的擦除操作.

当然, 这会引起一个副作用, Trim过的块的内容变得不确定, 那些反删除/数据恢复软件, 大概要集体师太了吧XD

写这文的本意是不希望那个诡异的说法以讹传讹下去, 之前还看过把超线程解释成双核的文… 不过不知道有多少人有耐心看完呢…

hhukcert.exe

image

这个hhukcert.exe是啥呢? 它是世界最大银行中国工商银行网上银行一种U盾的驱动的一个后台驻留程序, 如你所见, 它每隔一分钟会暴起一次, 占用大约50%CPU占用率, 持续时间约20秒, 注意这里是双核的情况, 如果是单核, 大约就是近100%的占用了, 占用内存26.6MB, 说实话我不太明白这玩意是怎么写到这么烂的.

脑残的智力题

    无聊闲晃, 看到个智力题, (本文引用部分为棕色, 正常颜色是点评)

    我个人所知道的最经典的逻辑推理题 ——-你智商达到180了吗?
    一个村子里,有50户人家,每家都养了一条狗。现在,发现村子里面出现了n只疯狗,村里规定,谁要是发现了自己的狗是疯狗,就要将自己的狗枪毙。
    但问题是,村子里面的人只能看出别人家的狗是不是疯狗,而不能看出自己的狗是不是疯的,如果看出别人家的狗是疯狗,也不能告诉别人。于是大家开始观察,第一天晚上,没有枪声,第二天晚上,没有枪声,第三天晚上,枪声响起(具体几枪不清楚),问村子里有几只疯狗?
    这是一道逻辑推理题,答案有且唯一。

    这个情景太有趣了, 到了晚上, 全村人扛着猎枪浩浩荡荡出发, 挨家扫荡, 看到疯狗, 狗主人之外的人端起枪乱枪打死, 狗主人痛哭. 可是不对啊, 这一晚上就扫完了啊? 干嘛还到第三天晚上?

    我不由得想起另一个题, 大意是: 有一幢三层房子, 每层有四个房间, 朝南的房间有两扇窗户, 朝北的房间有一扇窗户, 有一个烟囱, 请问房东老太太今年多大岁数了?

    不过我觉得这个题没有这么无厘头, 应该是被人转错了, Google一下, 找到这么一篇:

 

原题应该是这样的:   (颜色没标错, 这不是我写的, 有人站出来纠正)
  有一个小村庄住着50户人家,每户人家都养了一只狗。有一次村子里出疯狗了。大家在一起商议:每天上午大家都要到每一户人家去查看狗,一旦发现自己家的狗是疯狗时,必须在当晚开枪把自家的疯狗杀死。这村子的人家都有这样一种本领,就是能看出别人家的狗到底是不是疯狗,但是看不出自家的狗是不是疯狗。并且互相不能告知真相。第一天,第二天,村子没有枪声,到了第三天晚,村子里响起了枪声,村子里所有的疯狗都被杀死了。问村子里到底有多少条疯狗?  

(然后他贴了分析过程)
  首先:每个人都清楚疯狗是一定存在的  
  假设:有一个人发现他所观察的除自己外的49家里有48家是好狗,1家是疯狗,  
  由于对自己家的狗无法判断,因此这时候他得出结论:至少有1只疯狗,至多2只(加上自己家的)  
  如果是1,那么有49家的是好狗,自己属于“49家好狗阵营”;如果是2,那么有48家好狗,自己属于“2家疯狗阵营”  
  虽然他无发确定是1还是2,但是他会推理:  
  假如是1,即自己的狗也是好狗,只有他看到那只狗是唯一的疯狗,设其主人为a  
  那么a就会看到别人的狗都是好狗,而a又清楚一定存在疯狗,这只能是a自己的狗  
  因此a第一天就会开枪杀狗.  
  但是第一天并没有人开枪,  

  这就说明a并没有看到“别人的狗都是好狗”,  
  因此疯狗数不是1而是2,“有一个人”自己不属于“49家好狗阵营”而是属于“2家坏狗阵营”——除了自己和a之外的48家是好狗  
  所以第二天他就会开枪杀死自己的狗 

    没全贴, 意思大概明白了, 是说全村人出去挨家晃, 然后回家拼命推理, 这村儿里每家都有一个福尔摩斯, 推出自家狗是疯狗了就开枪, 不是说看见疯狗就开枪的, 别家的狗不能杀, 可是两篇都没有明确说明别家狗不能杀…

    还是有问题, 为什么天数跟疯狗的条数挂钩呢? 按照那个推理, 两条狗的情况, 第一天疯狗主人A和疯狗主人B各自只看到一条疯狗回到家, 疯狗主人A没有听到B的枪声(时刻1), 推出自己的狗也是疯狗, 于是开枪杀狗(时刻2), 疯狗主人B在时刻1和时刻2做同样的事, 时刻1和时刻2可以就在第一天, 只要这两个狗主人的思考速度足够, 于是两条狗的情况在第一天就被击毙了, 干嘛要等到第二天? 要让时刻1与时刻2严格对应到第一天和第二天, 推算还可以成立, 可是这个对应如何完成呢?

    还有一个问题, 同样情况下, 疯狗主人A没有听到枪声(时刻1), 推出自己的狗是另一条疯狗, 于是开枪杀狗(时刻2), 疯狗主人B在时刻1做跟A一样的事, 但B的动作比较慢, 在时刻2还没能杀掉狗, 这时候他听到了A的枪声, 他重新思考, A开枪了, 可能是(因为A没有看到任何疯狗, 于是推出A的狗是疯狗, 所以开了枪), 也可能是(因为A看到B的疯狗却没有听到B的枪声, 推出A的狗是另一条疯狗, 所以开了枪), 于是B无法判断自己的狗是不是疯狗.

    这个问题更严重, 明明A和B在一开始得到了同样的信息(看到对方的疯狗), 可是下场却是A开枪, B挠墙, 差别就在于B动作慢, 导致他比A多得到(对方开枪)这个信息, 同步问题.

    同步问题怎么解决? 很简单, 别用一开就会被听到的枪, 在家用刀悄悄的杀就可以了, 每天巡逻完, 各自回家, 推理, 然后决定狗是否要下锅, 第二天大家再巡逻看各家的狗煮了没, 这样大家就同步了, 时刻1/时刻2也得以与第一天/第二天对应, 分析过程可以成立.

    复述者根本没能理解到推理的真意, 复述中被无意加入/减少了他认为无关紧要的事, 原本好好儿的题目, 变成这样, 这是何等的师太啊!

    解原题智商要一百八, 能像我这样逆推出原题, 智商那得要一千八吧 -_,-