读历史首先是要看写这段历史的人的口碑和人品,再去看读者对这本书的评价,历史被歪曲的太多,没有经过沉淀的历史书籍从不敢读,黎东方教授的细说系列长久以来被认为是历史读物中的上品,而清朝又是和我们衔接最紧密的一段历史,对于清朝发生的那些事情多多少少都有些了解,却从来没有完整客观地知道那个时代都经历过什么,也从来没有对那个时代的人有一个客观的评价,于是鼓起勇气读完了《细说清朝》。
读这本书感觉作者仿佛一位说书人,将那个年代的历史对你娓娓道来,清朝瞬间的崛起,短暂的辉煌,上百年的内忧外患都在本书中尽然展现,这本书更好地帮我们了解了那个时代的历史,更好地了解了那个时代的人。
中国的历史是帝王的历史,相比之下美国的历史则是平民的历史,这一点也不假,那么厚的一本《光荣与梦想》也不过讲了区区四十年的美国历史,刨除几个大的历史事件,绝大多数篇幅都在描述民众生活常态,以至于读起来会感觉枯燥很多,甚至一部《阿甘正传》都能概括美国大半部历史,相比之下四十年在中国的历史长河中不过是弹指一瞬,中国有太多的四十年,有太多的朝代更迭,帝王更替,而在这漫长的历史中最不值钱的也最不值得一提的便是平民百姓,思想被禁锢被奴化的中国人最容易被历史淡忘,于是历史上只留下了帝王将相。
...
今天踩了一个伪随机数生成函数的坑,与其说是个坑到不如说自己功力不够深厚,对这些随机数生成的函数族欠缺了解,先来介绍下我的问题吧。
拿了100M的数据用LDA算法来跑,单线程的时候一次迭代需要大约15s的时间,而改用两个线程跑,线程之间对不同的数据块进行迭代,一次迭代完成的时间居然需要大约50s,而且线程数越多就会越慢,因为迭代的采样函数是一个纯计算的函数,多线程的情况下每个线程的数据量要比单线程成倍地缩小,迭代速度相比单线程应该快N倍才对,现在的结果是不符合常理的,因为每个线程都是独立的训练集,线程之前没有共享数据。
其实在我用几M的小数据测试的时候就发现这个问题,当时以为是数据量小迭代速度太快,以至于在迭代完成后的线程同步占用了一些时间才导致多线程版本会慢于单线程版本,但数据量大的时候这样就不可理解了。
后来开了两个线程发现,迭代计算的时候两个CPU大部分时间居然都没有跑在用户空间,相反大量的cpu时间都耗在了系统时间,仔细看了代码,这部分就只有一个random()函数不是我的计算函数,改成定值之后测试速度马上彪上去了,那就可以断写问题就出在这里。
random()函数是不可重入的函数,不保证它是线程安全的,但我看了glibc的代码发现, 其实它在glibc的实现里面是线程安全的:
...
网络上对于刘瑜的评论似乎趋向于两个极端,说她好的自然大有人在,说她不好的也不在少数,还有人调侃地把她和安妮宝贝和孤郭敬明相提并论,不同的人有不同的政治立场,刘瑜作为一名时评作家,她的观点自然有人赞同有人反对,这都无可厚非,不管是《民主的细节》还是刚读完的这本《观念的水位》,对我而言都是非常有营养的。
根据百度百科里面的介绍,刘瑜在《南方周末》写时评专栏,在《新周刊》写书评和影评专栏,也正像作者在序言中提到的,《观念的水位》这本书就是这些专栏文章的合集,所以前半部分大多是时政评论,后半部分就是书评和影评,我对书评和影评不太感冒,没有读过的书没看过的电影被别人一评价,这书这电影再看起来就没有原来的味道了,观点就会不自觉得被这些评论牵着鼻子走,所以对我而言前半部分的吸引力要远大于后半部分。这本书把一些离散的文章集合在一起,作者也没有刻意地去让他们之前有什么衔接,所以读起来思维可能需要有一点跳跃,比如前一篇在讲伯林墙,后一篇就已经在说曾国潘了。
书中有一篇文章名字和书名相同,以这篇文章的标题作为书名,我相信作者有她的意图,此书的出版意在提高读者的政治观念,文化观念,历史观念,因为只有民众观念的提高才能促成社会变革,这篇文章中有一段话我很赞同,在这里引用一下:
我心中理想的社会变革是一个“水张船高”的地程:政治制度的变革源于公众政治观念的变化,而政治观念的变化又根植于人们生活观念的变化。水涨了,般自然浮起来。我观察社会变革的动力,不那么关注船上有没有技艺高超的船夫,而更关注水位的变化。
...
多书,科幻玄幻政治历史,有些书是用来娱乐打发时间,有些书是为了开阔眼界,丰富内涵,每读完一本总会有些许的思考,但却一直没有把读完这本书带来的收获记录下来,今天决定开始对读过的>每本书写读书笔记,不能让这些书的内容只是作为过眼云烟,记录下来也算对自己有所沉淀。
黄仁宇的这本《万历十五年》是从杭州回北京的飞机上读完的,读这本书花了不少时间,这期间也主要因为工作太忙,工作之余还要抽出时间来补专业知识,所以就冲淡了读这些文学作品的时间。出差唯一的好处是可以>在旅途中读书,这个过程是很享受的。
《万历十五年》这本书写的是万年皇帝第十五年也就是公元1587年前前后后的历史,作者黄仁宇博士履历丰富,学识也很渊博,《万历十五年》在我看来没有博人眼球的华美文字,字里行间也是朴实无华,作者站在一个>后来人的角度上客观公正地去审视那个年代的历史,为我们重现了一个典型的中国封建王朝有政治和民生。
...
Sheepdog的块设备驱动写好有一段时间了,陆续修改了几个版本之后,近期进行压测的时候遇到一个死锁的问题,头痛了一个多星期,今天请教了一下淘宝内核组的@伯瑜同学,在他的热情帮助下分析出来了死锁出现的原因,解决的办法暂未找到,或者说这问题无解,待我细细说来。
问题是这样的,在把Sheepdog中的某个VDI挂载成块设备之后(/dev/sheepa),我在sheepa上安装了一个debian,然后启动QEMU,启动盘就设为/dev/sheepa:
qemu-system-x86_64 -m 512 -hda /dev/sheepa
启动完成后开始狂做IO,也没用啥复杂的办法,就是dd
dd if=/dev/zero of=xxx bs=4096 count=1000000
就这样在写入几个G的数据后就有可能会出现死锁,而且出现的机率很低,复现一次要花好长时间,有时候几十个G的磁盘都被Sheepdog写满了也复现不出来。死锁发生时,sheep其中一个进程会D住(一个sheep会启动两个进程,一个是主进程,一个是日志进程),这时候QEMU也会hang住,甚至在有些极端的情况下ps -ef也会hang住。
我在sheep block driver里面加入debug信息定位到hang住的位置,是在read_reply()这个函数里面,这个函数是在等待sheep的请求响应,这个时候sheep已经hang住当然不会响应,于是QEMU的IO一直没有返回,也会一直hang在那里,可为什么sheep会hang住呢,这个问题是当时我没想明白的,后来经过伯瑜大神的指点才明白过来。
...
最初刚开始玩Sheepdog的时候就想着要是能把它作为一个像硬盘一样的块设备,直接挂在终端机器上就好玩了,直到最近工作不是特别忙的时候才有时间想想这事情,花了好几个晚上终于把给Sheepdog写好了一个块设备驱动sheepdev,可以把集群中创建好的VDI直接注册到kernel中,然后使用用户态的相关工具fdisk/mkfs/mount等对这个块设备进行分区格式化挂载等,代码已经提交到upstream,至于还要修改几次,最终能不能merge到upstream中去都还不确定,先简单记录一下自己的工作经历。
块设备驱动作为一个kernel module,在module init的时候我注册了一个proc entry /proc/sheep,通过这个proc entry对这个块设备进行控制,比如:
echo “add 127.0.0.1:7070 a5d05d” > /proc/sheep
可以将VDI Id为a5d05d的VDI作为一个块设备安装到本地,/dev目录下会出现一个/dev/sheepa这样的块设备文件,添加第二个后出现/dev/sheepb,以此类推。
也可以通过下面的方法来删除已经注册上来的块设备:
echo “del sheepa” > /proc/sheep
在安装块设备的时候根据用户提供的VDI Id和sheep地址,首先来向sheep创建一个长连接,并通过该连接向sheep获取该VDI的inode数据,该长连接创建后会一起保持用于driver与sheep的通信,只有获取inode的过程是同步的,后期的读写操作都是异步进行的。
...
前一篇日志从Checkpoint的角度分析了BLCR的软件架构,没有写最核心的做dump操作的那部分代码,这部分代码完全是在内核态运行的,涉及到进程的各种状态,包括进程的PID/PGID,虚拟内存映射,打开的文件,寄存器的状态,credentials,timers,信号状态等等。
要提一下的是昨天淘宝内核组的@RoverYu同学给我看了一篇LWN上的文章,http://lwn.net/Articles/525675/,这个东西叫CRIU(CheckPoint/Restart in user space),是在用户态实现进程的Checkpoint/Restart,虽然是用户态的CR,但这种事情没有kernel的配合肯定是做不来的,我没有仔细去研究CRIU的实现机制,只是看了下简单的介绍,貌似是添加了一些相关的系统调用,否则这种事情单靠用户态程序肯定是办不到的,比方说PID做Checkpoint的时候有getpid()这样式syscall,可以得到进程的pid然后保存在文件里面就可以,但Restart的时候可没有setpid()这样的syscall可以用,当然CRIU和kernel进行通信也用到了/proc文件系统,相比之下BLCR和kernel通信完全只用了/proc文件系统,之后就把CR所有的工作都扔给内核去做了,在kernel中进行Checkpoint最核心的函数是cr_dump_self(),也就是进程通过ioctl向kernel发送CR_OP_HAND_CHKPT请求之后kernel对应的处理函数,接下来仔细讨论下这个函数。
对应于进程的每一个子进程或者线程都会执行这个cr_dump_self(),也就是每个task_struct对于一个cr_dump_self(),对于共享mm_struct的线程而言,这些函数只有其中一个dump mm即可,其它的只是保存一下进程的寄存器状态便可以了。
...
BLCR(Berkeley Lab Checkpoint/Restart)简单地讲是一个对进程做Checkpoint/Restart的套件,实现了用户态的libcr库和kernel module来完成相关的Checkpoint/Restart工作,最近在阅读BLCR的代码,也简单地hack过代码,写这篇文章来记录下我对于BLCR的理解,先暂时只写Checkpoint相关的BLCR架构流程。
1. BLCR的用法
对于一个进程如果需要对它进行Checkpoint,那么它首先需要具备以下两个条件之一:
- 进程通过cr_run启动,如cr_run ./test
- 进程在编译时链接了libcr库,如gcc -o test test.c -lcr
上述两程方法是等价的,即如果test在链接时未链入libcr,那用cr_run启动它也可以进行Checkpoint,同样,如果一个进程在编译时链接了libcr,那么启动时无需使用cr_run进程启动也可以进行Checkpoint.
假设刚启动的进程pid为3030,那么对该进程做Checkpoint可以简单地通过下面的命令来完成:
BLCR在完成后默认会生成一个context.3030的文件,里面包含了进程运行的几乎所有信息,可以通过该文件Restart该进程,如:
$ cr_restart context.3030
...
Common Lisp进行网络编程可用的库还是挺多的,比较常用的库有usocket和iolib,usocket我简单了解了一下没有真正拿来用,它的API比较简单,文档写得比较全面,相比之下,iolib要比usocket强大的多,但缺点是文档太少,官方的文档可用的内容非常少,但如果能阅读一下iolib的相关源码,就会发现其实iolib是一个很强大的网络编程库,其中包含了DNS解析,socket基本操作(bind,listen等等),IO多路复用以及通常用来做IPC的socketpair,而且iolib的multiplex用起来有种libevent的感觉,用iolib可以实现一般的应用层网络编程,至于是否支持raw socket,我还没仔细研究,不过感觉应该问题不大。
1.iolib的安装
使用asdf-install可以在线安装iolib,但貌似asdf-install不会自动解决包的依赖问题,最近才发现原来asdf-install其实已经是一个废弃的项目,官方已经不推荐使用了,在cliki的asdf-install首页最开头就有一句醒目的提示语:
ASDF-install is OBSOLETE. DO NOT USE ASDF-INSTALL, EVER. DO NOT ASK AROUND ABOUT HOW TO GET IT RUNNING. IT IS O-B-S-O-L-E-T-E. Not working. Not maintained. Please use quicklisp instead.
...
前段时间在学Common Lisp,接触新语言我干的第一件事一般是通过HTTP抓取某个web页面,因为对网络编程比较感兴趣,而且平时写的程序也多是网络相关的,所以比较关心这方面的用法,于是用IOLib写了一个简单的小程序尝试着抓取了几个大门户网站的页面代码,关于IOLib的基本用法改天我也写篇日志记录一下,也算是和大家分享一下,毕竟能找到的中文资料比较少,而且文档也不是特别全,就像这篇文章里面说的:”Such is the nature of open source documentation. “,于是大多数的用法都得通过hack源代码来弄明白,言归正传,在写这个小程序的时候我遇到了一些问题,关于字符编码的问题,下面慢慢道来吧。
IOLib的receive-from方法是通过调用recvfrom来进行的,这种带缓存的接收方式很符合其它语言进行编程的套路,但它所接收到的buffer数据是需要存储在一个vector ‘(unsigned-byte 8)中的,虽然字符串在本质上也是向量,但对于字符串的很多操作不能直接应用于vector,而且vector中的元素都是每个字符的unicode编码,而不是确定的字符,于是便需要进行转换,最初我使用的办法:
(map 'string #'code-char buffer)
...
Recent Comments