一个文件的长度和它实际所占用的磁盘空间很可能是不同的,这主要涉及到稀疏文件(sparse file)和文件打洞(hole punching)的概念。这两个特性需要操作系统和文件系统的支持,目前Linux的ext4、XFS等文件系统都支持这两个特性。 稀疏文件 (Sparse File) 了解系数文件最直观的例子是,创建一个文件,然后用lseek定位到较大的偏移量,在这个偏移量实际写一些内容,这时实际占用的磁盘空间很小,但文件的长度却比较大。比如: #include <fcntl.h> #include <assert.h> int main() { // 打开两个文件file_normal和file_sparse int fd = open(“file_normal”, O_RDWR|O_CREAT, 0755); int fd_sparse = open(“file_sparse”, O_RDWR|O_CREAT, 0755); assert(fd != -1); // 一个从0写入3个字节,一个从1000偏移写入3个字节 lseek(fd, 0, SEEK_SET); lseek(fd_sparse, 100000, SEEK_SET); write(fd, “ABCDEFG”, 3); write(fd_sparse, “ABCDEFG”, 3); close(fd); close(fd_sparse); return 0; } ls的-s选项可以在第一列打印出文件所占的磁盘空间: zjc@~$ ./sparse_file zjc@~$ ls […]

为了统计代码行数(lines of code, LoC),最简单的思路是用python读取每个所输入的代码文件的行数,然后加起来。 本实现分离了代码文件识别和统计,代码文件由用户给出。 1. 实现: Python实现,用enumerate函数统计可以防止内存占用过大的问题,我们要的只是一个计数,每行读完扔掉即可(pass)。代码如下: #!/usr/bin/env python import sys def file_len(fname): with open(fname) as f: for i, l in enumerate(f): pass return i + 1 file_n = len(sys.argv) – 1 print file_n, “files:” sum_line = 0 for i in range(file_n): this_line = file_len(sys.argv[i + 1]) sum_line += this_line print this_line, “\tLoC\t”, sys.argv[i […]

Bloom Filter 和 Cuckoo Filter有类似的用途,很多人将它们称为概率数据结构或者近似成员数据结构(approximate membership data structure)。最近看了一个Bloom Filter和一个Cuckoo Filter的比较好的实现,代码都是用C++实现,代码量也不大,读起来没有什么难度。 本文贴出来的是两个项目的大体构成,不涉及到空间、错误率等的理论分析,希望能给需要的新手一些帮助。 两个项目的网址如下: C++ Bloom filter library: https://code.google.com/p/bloom/ Cuckoo Filter: https://github.com/efficient/cuckoofilter 1. Bloom Filter (https://code.google.com/p/bloom/) 源码目录: $ tree . ├── Makefile ├── bloom_filter.hpp ├── bloom_filter_example01.cpp ├── bloom_filter_example02.cpp ├── bloom_filter_example03.cpp ├── random-list.txt ├── word-list-extra-large.txt ├── word-list-large.txt └── word-list.txt 文件包括三个用于测试example、三个用于测试insert的txt词典,bloom filter的实现在bloom_filter.hpp中。 bloom_filter.hpp中包括3个class:bloom_parameters、bloom_filter和compressible_bloom_filter。其中bloom_parameters是构建一个BF需要的参数,compressible_bloom_filter 类继承自bloom_filter类。 1.1 bloom_filter.hpp bloom_parameters 包含的成员: // […]

Consistency这个词在计算机各领域用的很多,比如分布式系统、体系结构和存储系统等等。本文只探讨存储系统crash consistency。Crash Consistency问题在存储系统中都会存在(数据库、文件系统、dedup系统 …),即系统遭遇断电、崩溃等情况时,相关联的数据没有全部持久化可能导致的不一致。本文以文件系统为例进行说明,所有内容基于自己对相关资料的理解,如有错误,恳请指正! 崩溃为什么会导致不一致 下表整理自我的OSTEP笔记[1],我们假设了一个有data和inode、bitmap两种metadata的简单文件系统,下表给出了一些可能导致不一致的情况,其中N表示断电时没有写完,F表示断电时已经完成: 多种metadata之间的一致性通常最麻烦:如上表的inode和bitmap,他们之间存在相同冗余信息(bitmap可以从inode推导出,但是这个推导是要遍历所有inode的,bitmap的作用就是用冗余的信息换取性能),并且由于并非在一个磁盘块,无法原子地同时更新,所以如果掉电时只有两者之一成功更新了,那么它们之间相同的信息便存在了不一致。metadata和data之间也存在不一致的情况:如上表中,若两种metadata都更新好了,但是data写到一半掉电了,那么下次开机后根据metadata读data时就会读到坏的数据,因此可以称为不一致。 追究其根本原因,是存储系统中底层硬件的一次磁盘I/O(512字节),无法保证上层的一次请求的相关联的所有data和metadata的原子写入;反过来想,如果上层的每次请求中data和metadata都连在一起且小于512字节,那么就不用额外的一致性机制保证Crash Consistency。 保证一致性的方法–以WAL为例 由于硬件或者底层的原子写单元和上层存储系统一次请求所涉及的更改不匹配,所以我们只能在上层存储系统中用额外的手段保证crash consistency,常用的方法有: WAL(Write ahead logging, 也叫logging或journaling), CoW(Copy-on-Write, 也叫shadow paging), log-structuring, ordered write, soft updates等等。本文只简单举例说明一下WAL这种最常见的方法如何保证crash consistency: 比如,WAL为了保证bitmap和inode等不同种metadata之间一致性,在更改metadata时,一定要先将这些metadata写入到磁盘上的log区域,然后再对目标位置的metadata进行更改,这样,如果系统在写log时掉电了,原始的metadata没有影响,如果在写原位置metadata时掉电了,又可以在开机时从log进行重做(所以文件系统中的WAL类似于DBMS中的redo log)。 不同人对一致性有不同的认识 对于一个对任何事要求都很低的人来说,也许只有文件系统由于crash而被破坏了、不能再正常使用了才是不一致;他可能认为仅仅metadata和data的不一致可能并不算不一致,因为文件系统还会正常工作,只是被FS服务的用户或应用得到了错误的数据,谁叫他把电线拔了呢?。因此对一致性的定义、对一致性强弱的要求也是因人而异,因系统设计目标而异的。 比如,ext4是一种基于WAL的文件系统,具体提供了3种logging模式:journal, ordered(default), writeback。这三种方法对一致性的强度依次减弱,可以帮助我们理解为什么不同人、不同场景需要不同强度的一致性:journal是把所有data、metadata先进行logging[2];ordered是用ordered write的方法保证data和metadata的一致性,用logging保证不同类别metadata之间的一致性,ordered write指但是先写data完成,再写metadata的顺序,data因此也不用进行logging;writeback则不管data和metadata的先后顺序,data也不写log,可能刚刚提到的要求很低的人和对性能要求更高的人才会用这个参数吧。 摘自kernel文档[2] data=journal All data are committed into the journal prior to being written into the main file system. Enabling this mode […]

本文是对《A Primer on Memory Consistency and Cache Coherence》这本书前一半内容的记录和理解,主要涉及memory consistency model。 1. 引言 对于多处理器共享内存系统来说,consistency和coherence都关注的是共享内存(shared memory)及cache的正确性问题,而人们把这个问题拆成两个方面是为了更好地将这个复杂问题分治解决。 1.1 Consistency 一般需要被详细讨论的是多核(或线程)共享内存(shared memory)的consistency模型,因为单核单线程问题相对简单直观。内存consistency模型规定的是:多线程同时进行load/store操作时,怎样的执行顺序是对的,怎样是错的。比较简单直接的consistency模型包括sequential consistency、TSO(total store consitency,x86使用)等。 1.2 Coherence 本文主要记录与consistency有关的内容,但因为consistency的实现与coherence有关,所以要简单介绍下coherence及其与consistency的关系。 虽然coherence的中文也翻译成“一致性”,但coherence这个词通常跟在cache后面,即缓存一致性(cache coherence),解决缓存一致性问题的方法也被称为缓存一致性协议(cache coherence protocol)。那么共享内存系统的cache为什么需要coherence协议保证共享内存系统正确性呢?这是因为cache一般分为L1、L2和L3等很多层,L1等比较高的层级中,cache是每个核所独占的,一般只有L3、memory等层级才是共享的。在每个核独占的层级中,可能出现统一内存地址的数据在不同独占cache中数值不一样的情况,这时cache的状态可以称为incoherent。通过无效化等coherence协议,可以保证多核系统cache的正确性。 1.3 Consistency 和 Coherence的关系 对于sequential consistency和TSO等比较简单的consistency model来说,保证了coherence的cache可以被看成一个“黑盒”甚至对consistency model透明,黑盒中有cache实现有保证cache使用正确的coherence protocol,而consistency更关注程序(或处理器核)的访存顺序。因此对于简单的consistency model和coherence protocol来说,两者是解耦的。 1.4 一个小例子 如果上边几段不易理解,作者在书中用一个例子解释了这两个名词的基本含义,简单记录如下,有改编: consistency的例子 设想有三个人,计算机体系结构课程老师、教务处网站管理员和上课的学生,老师最开始在教务处上登记了上课的地点是152教室,但是开学第一节课后发现选课的人太多了152坐不下,于是准备下节课开始换到更大的252教室,于是老师先①找教务处网站管理员说“请你把网站上我课的教室信息改到252(要求①),随后通知学生们去教务处网站查询下节课的上课地点(要求②)。这就产生了一个问题,网站管理员可能是第二天才更新的网站,而学生是接到老师的通知马上重新查看了教务处网站,因此学生下周又来到了152教室,老师的计划和最后的结果出现了不一致情况。 问题就出在老师的做法无法保证学生在网站被修改之后再去网站查询。要想保证学生查到正确的信息,一种简单的办法就是保证管理员的确更新了数据,然后再通知学生们。这种简单的办法就可以称为一种一致性模型。 我们把这个例子对应到实际的内存系统中,给管理员和学生要做的两件事(要求①和②)可以分别看成一条store命令和一条load命令,目标都是教务处网站上老师的教室号,这个目标可以看成同一块内存地址,因此对同一内存地址执行的store和load命令是否可以调换顺序(管理员在学生查询才修改了网站),调换顺序后是否破坏了程序的正确性,就是内存一致性模型memory consistency model所负责的。也就是说,出现上述情况算不算错,应该是当前的一致性模型所判断的:相对于我们每个人心中直觉上的一致性模型,这种走错教室的情况肯定是错了,但是对于一个性格怪异的老师,也许他觉得这样也是对的,比如他可以找他的同事帮他上152教室的课,他自己上252教室的课,也正因他如此怪异,所以他最开始联系网站管理员时也遵循了他心中的怪异的一致性模型,没有等网站确实修改就给学生们发了查询教室的通知。 coherence的例子 紧接上个例子,与之不同的是,很多学生在最开始选课的时候就把《体系结构》这门课的教室152记在了自己的小本本上,但是后来,管理员将网站上教室信息改成了252。虽然学生的小本本上和教务处网站上的信息应该是同一个信息,应该是一样的,但是这时两者一个152,一个252,这就出现了incoherent的情况。 在内存系统中,学生的小本本就相当于cache,而教务处网站相当于memory,学生将memory中的某个值拷贝到了cache中,当memory被其他人更新时,学生自己的cache就应该同时立即处于无效的状态。这里出现incoherent的原因就是没有一个cache coherence protocol来保证cache的正确性。比如,一个简单的coherence protocol可以这么干:在网站更新后,老师挨个找到每个学生,把他们的小本本记的152划掉?,无效化协议就是这种思想。 2. […]

我们应该怎么分析QEMU代码中某段代码的性能呢?除了比较复杂的trace-event功能(我的博客中翻译过qemu tracing的文档),其实在QEMU自带有一个简单的profiler实现,它是一个简单的计时器封装。这篇博客主要介绍怎么在编译时开启、使用QEMU profiler,并说明怎么利用这个功能添加一个自己的计时器来分析QEMU中某段代码的性能。 1. 编译 我的代码是QEMU 2.12.0。要开启profiler功能,在编译前进行运行configure的时候,只要加入–enable-profiler选项就可以了,它会加入CONFIG_PROFILER这个宏定义。比如我用如下选项进行编译: cd QEMU_SRC_PATH ./configure –prefix=/PATH/TO/QEMU_BIN_DIR –target-list=x86_64-softmmu –enable-profiler make -j make install 将其编译到QEMU后,无须改动启动参数,它是默认启用的,但是我们一般需要用QMP shell来查看它帮我们计时的信息。 2. 使用 在启动QEMU虚拟机的命令中,我们需要加入一个QMP socket,用于一会接入我们的QMP shell: # -qmp后边接我们要创建的QMP socket文件的信息,这里我们将它创建在本目录(./qmp-sock文件) /PATH/TO/QEMU_BIN_DIR/bin/qemu-system-x86_64 … -qmp unix:./qmp-sock,server,nowait 在虚拟机启动后,用QEMU源码中自带的QMP shell脚本连接QMP socket: # 这个脚本就是QEMU源码中的scripts/qmp/qmp-shell文件 # 加-H是为了以HMP命令进行交互,否则就得使用json格式,不方便 /PATH/TO/QEMU_SRC/scripts/qmp/qmp-shell -H ./qmp-sock 之后出现以下欢迎界面: Welcome to the HMP shell! Connected to QEMU 2.12.0 (QEMU) 我们在(QEMU)后面输入info profile就可以看到QEMU自带的两个计时器的数值,每次查看完这个数值,数值会清零。 Welcome […]

日记式的个人胡扯,没有一句话保证正确,谢谢围观,欢迎指正。。 通用与专用,没有好坏 首先举两个极端的例子:深度学习应用十分重要,因此人们愿意专门为它花钱设计新型专用芯片和硬件架构,甚至可能为了它的性能,没准以后会重新写了一个叫”DnnOS”(我自己瞎编的名字)操作系统;而Jc写的helloworld.py程序无论在Linux, Windows 95还是Win 10上怎么折腾,都是打印一行hello, world,没有任何区别的。 哪个更好的问题没有绝对的答案,也许深度学习的新型硬件没有键盘鼠标和显示器,DnnOS也只要实现一套新型硬件的驱动,复杂程度远远小于Linux和Windows。但是Jc的helloworld.py无论运行在多么复杂的系统上,都无法到一个好的深度学习模型所带来的价值;反过来说,即使这套新型深度学习工具再牛逼,可能都无法运行Jc的helloworld.py程序。 所以,废话就是,当然是各有利弊。 什么应用需要专用系统, 首先当然是嵌入式设备,有些嵌入式设备并没有操作系统,有些有经过精简的操作系统。为实际应用量身定做的硬件和软件,对权衡性能和成本应该是最有利的! 另一种是,在我看来,是专用服务器,比如一台专门的数据库服务器,那么首先它的硬件选型是很重要的,比如存储设备要选高端的,显卡就不要了;它的操作系统的很多东西就用不上了,比如DBMS通常会关掉OS的文件缓存page cache,甚至不用OS的文件系统,来自己管理缓存和裸块设备,包括很多多余的硬件驱动都是不必要的。 什么应用需要通用系统 最易想到应该使用通用系统的例子,就是每个人的手机还有个人电脑了,由于每个人的爱好和工作习惯不同,它们的任务多种多样,资源利用的特点也各不相同。80年代的PC、00年代的手机,都是以计数器、画图、记事本功能齐全作为卖点,后来随着系统的发展,甚至会搞出应用商店这种来增加系统的功能,这时,工作负载就更不唯一。这样,在为每个用户量身定做系统不现实的情况下,只有系统更通用才会更满足消费者的多样需求(比如有人爱拍照,有人爱打王者荣耀)。 另一种,可能是云,也就是各种虚拟化和分布式技术。原因很简单,租用云服务的用户所需要的不只是一种服务(可能是云主机、云数据库或者云存储),更重要的是负载也是无法预测的。最典型的例子是云虚拟机,这时,一个“需要通用”的操作系统运行在云上,那么这个云更通用,比通用OS还要通用。比如,一个可以称为“云操作系统”的系统,要保证计算、存储、内存的可伸缩性,这时一般OS是不提供的,还要保证运行和数据可靠,这都是通用(通用虚拟机)之外的通用(伸缩性、可靠性)。 通用也是专用 讨论了什么时候应该通用和专用,及其原因之后,突然觉得:通用也是专用,因为不管是通用的还是专用的。因为专用的本来就是专用的;而通用的,开发它们多数都是 专用 来赚钱的,不管是手机还是云。

“写放大”(Write Amplification)在存储系统中是很常见的。但是,即使都是在存储系统中,“写放大”也有很多种,各种的写放大原理并不是很一样。下边根据自己的理解,进行了下总结,如有问题,恳请指正。 1. 读写单元较大导致的写放大 在文件系统中,读写单元固定,比如都是4K,这样,如果write函数写的数据小于4K,则要先把整块读入,再修改,再把新的4K整体写入(O_DIRECT情况除外)。这个过程可以称为 RMW (Read-Modify-Write),这就是File System的写放大问题。[1][2][5] (注意:Read-Modify-Write被更广泛地用在原子指令[3]和RAID[4]中。) 再如,在DBMS等应用层存储系统中,同样存在自己管理的读写单元,如MySQL的默认读写单元称为页,默认是16KB,所以一次读写只能以页的单位进行,这时,小于页的数据读写同样会带来整页的读写,进而造成了“写放大”,道理和文件系统是一样的。 2. RAID中的Read-Modify-Write造成的写放大 如前段所述,RAID中更新一个块,需要额外读原始块、校验块,额外写校验块,所以多了两个读,一个写,也称为Read-Modify-Write[4]。 这是由于校验块必须更新,且根据异或运算的可逆性,新校验块=新数据块^旧校验块^旧数据块。 3. SSD中闪存特性造成的写放大 在SSD中,一个block可以分为多个page,在读的时候,可以以page为单位,但是写的时候,只能以block为单位。因此写的单元比较大。在上层(比如文件系统)读写单元相同的情况下,同样是读写1个page的大小,读的话直接读就行,写的话却需要先把与要写page同一个block的数据全复制一遍,加上修改的page后,再一起写入block。写入的数据量远比实际的大,这就是SSD的写放大问题。 4. 存储系统一致性机制造成的同步写放大 在存储系统的很多层次中,都有保证系统crash consistency(一致性)的设计。因此,不管是应用层的存储系统(如DBMS、KV-store)、虚拟化层中的镜像管理、系统层的文件系统,甚至是硬件层的SSD FTL[7],都要通过强制同步各种元数据的写入顺序,或者利用redo log的思想,用journaling、log-structured或copy-on-write等策略保证元数据写入目的位置生效前先完整地生成日志,来保证系统崩溃或断电时,元数据之间是一致。但是,如果多层存储系统重叠,由于一致性机制导致同步次数增加就会层层放大。 比如,运行在x86虚拟机中的levelDB,其一次更新操作就会(1)最终导致levelDB写log文件和写数据两次同步写,这两次写就又会(2)导致2次的Guest文件系统log写和2次Guest文件系统数据写,一共4次同步写,这4次写又会导致(3)虚拟化镜像管理层的4 x N次写(N取决于镜像为保证元数据crash consistency的同步次数,若是qcow2格式,N可能有5次之多[6]),最后导致(4)Host文件系统的4 x N x 2 = 8 x N次同步写。当然这是一种比较极端的情况,但实际应用中也应该存在。 5. 基于LSM树的KV系统的Merge操作造成的写放大 levelDB等KV存储广泛采用了LSM树等结构进行存储组织,其特点就是靠上的level的数据会最终被merge sort到下层,由于多数level在磁盘文件中,这也就导致了同一KV数据的总写放大,放大的倍数就是大约是level的数目。和前边4中写放大不同的是,这种写放大并非写操作时马上就会发生写放大,而是写操作发生时会潜在的导致“未来会发生”写放大,所以这种写放大只会导致整体写代价提升,不会影响实时的延迟性能,只可能会影响磁盘带宽或者在SSD做存储设备时影响闪存耐久。FAST 16上有篇论文也专门分析了这种写放大。[8] [1] Why buffered writes are sometimes stalled, http://yoshinorimatsunobu.blogspot.com/2014/03/why-buffered-writes-are-sometimes.html [2] Block size and read-modify-write, https://www.spinics.net/lists/linux-xfs/msg14456.html [3] […]

出于某种目的,你可能不想把levelDB的所有的文件都存到一个目录下: 我们希望的: level 0 -+ level 1 +–> DIR1 (DISK1) level 2 -+ —————————— level 3 -+ level 4 | … +–> DIR2 (DISK2) level N -+ 但是 levelDB 不支持类似的选项,只能将文件存到一个目录;而且不幸的是,levelDB由于频繁的compaction操作,带来了频繁的文件创建和删除,且每个level包含多个文件,不易这样改。 我想到的方法有两个:(1) 用基于levelDB改进的RocksDB,它支持多路径。(2)修改levelDB源代码。为了更简单的实现我们想要的分level存到不同目录的功能,我们从levelDB存储的最底层“创建文件”步骤,利用软链接进行修改。 本文将首先介绍levelDB的目录结构,然后分析给出介绍这两种文件更改路径方法。 1. 目录结构 创建一个DB后,和这个DB相关的所有数据都会放在一个文件夹的多个文件中。这些文件包括xxx.ldb、xxx.log、LOG、MANIFEST-xxx、LOCK、CURRENT等。这些解释在[1]中说的都很清楚,我可以用中文再解释一遍。 日志文件 xxx.log xxx.log文件包括是最近存储的数据序列,所以是大小是乱序的,当xxx.log文件达到一定的大小(默认4MB),就会被转换成Sorted tables有序表文件。这个日志文件对应内存中当前的memtable,当这个memtable满了后,会被写到level-0,对应的xxx.log文件会被删除,新的xxx.log会被生成,对应于新的memtable。 有序表文件(SSTable) xxx.ldb SST是Sorted Strings Table的缩写,levelDB中,对应的文件格式是ldb。xxx.ldb文件中的KV记录是按key的大小排好序的。随着数据量增加,ldb文件有很多。但是,它们文件名前缀数字、文件大小都与所属的level无联系(文件名即文件大小都不包含level语义),所以我们无法从文件名和文件大小判断出某个文件中数据所处的level。不过,一个文件只可能属于一个level。 除level-0外,各个level的文件总大小是预先设定的,level-1 10MB,level-2 100MB, level-3 1000MB……;而level-0较特殊,其由文件个数限制,默认达到4个level-0 ldb文件就会merge到level-1中;而且,level-0中的数据可能有重叠存在。 清单文件 MANIFEST 我们从xxx.ldb文件名和大小无法判断其所属level,那么就要有一个额外的文件存储这些“元信息”。MANIFEST-xxx文件就负责存储哪个文件属于哪个level,每次打开这个DB,都会新建一个清单文件并标一个特殊的后缀作为标记,其中的内容也是以log-structured形式追加存储的。 当前文件 […]

《人有人的用途》(The Human Use of Human Beings — Cybernetics and Society)这本书是控制论鼻祖维纳(Norbert Wiener)的一本“科普书”,虽然只有100多页,我却是一本有深度的好书。第二部分笔记是书的第4~6章。 我曾经看过两本和经济学相关的畅销书,这种经济科普书中,常见类似“让你像经济学家一样思考”的宣传。书呢看了的确挺爽,思考世界的方式也很新鲜,但是看完之后并不能在头脑中留下系统的经济学知识体系,因此,这让我一直认为这类“经济科普”都是速食垃圾,读不得。 但这次再看完《人有人的用途》的几章,却动摇了我对那些科普书的看法。这是因为虽然我的专业与维纳相关,但我却从没有像他那样用信息、控制、反馈、计算、博弈的观点重新审视过这个世界。我虽不完全同意维纳所说,但就像经济学家可以用经济学的视角看世界,维纳也在用他的控制论视角看世界。如此看来,那些经济畅销书,还是有用的,不过我还是感觉先学经济知识,再看它们也许更好。 这三章中,维纳分别从控制论的角度描述了人类语言、有机生命和社会法律和人类的关系,下面是摘录和思考。。 第四章 语言的机制和历史 维纳的父亲是个语言学家,这章的篇幅也算是书中很长的。 (摘录)语言,从某种意义上讲来,就是通信自身的别称。 维纳认为人的语言、符号能力要远强于动物,这在于两方面:第一,信码是精巧和复杂的;第二,信码是有高度任意性的。 (摘录)人对语言的兴趣似乎是一种天生的对编码和译码的兴趣,它看来在人的任何兴趣中最近乎人所独有的。 虽然人类的语言的通信一般用于任何人的交流,但是维纳认为,用到人和机器、机器和人、机器和机器之间也是完全可能的。 (摘录)从线路到机器,中间还有一个转换过程,在这个阶段中,信息可以逸失而永不再得。……如前所述,这乃是热力学第二定律的控制论形式。 语言在进化的过程中也在和自然的通信干扰作博弈,比如一些人造语的词长分布和自然语言明显不同。 (摘录)语言的磨损可能是由几个原因引起的。语言也许只是力图反抗跟它捣乱的自然趋势,也许只是力图反抗人们有目的地搅乱其名义的企图。 把语言看成博弈,可以区分语言的两个变种:其一的主要目的是传送信息,另一的主要目的是把自己的观点强加到顽固不化的反对者头上。 维纳把人看做一种终端机器,那人和人之间就构成了通信网络,人和人的通信就分成了3个阶段: 语音阶段:人耳和脑中可能还存在类似滤波器的东西,高于或低于某个频率的声音即使有再多信息也无法接收。 语义阶段:如上所述,首先输入脑中的语音才能被解析出语义;且语义的翻译依赖长期的历史记忆;当一种语言和另一种语言不完全对等,就存在语义流动上的障碍。 (摘录:外国人讲的英语,是语义学上好的而语音学上差的英语;而普通人的酒后谈话,则是语音学上好的,语义学上不好的。) 行为阶段:指的是人由接收到语义可能导致的行为。 这三个阶段,信息量其实都是在减少的,这也符合热力学第二定律,如果信息在信道中被进行了任何干预,原有信息量必然是减小的,除非中途进行 馈进 。 (摘录)作为一门控制语言逸失的学科,控制论应用于语义学方面的愿望已经在若干问题上得到了实现……对行动有重要意义的,与其说是发出的信息量,不如说是进入通讯装置和存储装置的足以行动扳机的信息量。 第五章 作为消息的有机体 本章把有机体生命类比成消息。(有机体与混乱瓦解,正如消息与噪声间的关系) (摘录)在趋于毁灭的世界中,声明就是此时此地的一个孤岛,生命体抗拒毁灭和衰退这一总流的过程叫做稳态。 (摘录)……(我们会)生活到我们衰老速度大于更新速度为止 维纳认为人类等有机体可以看成一种 模式,这是因为我们的身体在不断代谢,组成人体的物质并非一成不变,只有“模式”是永存的。维纳的这种思想让我想到了当今的软件之于硬件,磨具之于产品,更直接的:3D打印。不过维纳更想说明的是,人类等有机体只是一种信息的形式,信息的传递比物质的传递更重要。(摘录:模式就是消息,它可以作为消息来传递。) 如果通信分为两种:物质运输和信息运输,那么两种之间也没有什么不可过渡的,只是当前的技术无法实现如此大量的基因数据传递(即使现在也不行),但是即使是人被交通运输向其他地方,维纳还是认为那本质上来说还是信息的运输。 以人体生殖细胞的结合与分裂为例,维纳认为“两部原先不相耦合的大型机器有可能耦合起来,从而从该阶段起像一部单一的机器那样工作。”,这我不禁想到当今的分布式系统、云计算的概念。 第六章 法律和通讯 正如第四章所说,语言是通信的形式之一,而法律则是语言的作用之一:用来“道德控制”。我觉得,媒体或者舆论应该在这方面也是类似的,都是用语言作为信息,让发信的一方的思想影响接收信息的思想,法律、新闻、舆论引起的社会后果便是信息传递后的反馈,这种反馈会再次作用到发信方,进行下一次“控制”。这种思想在维纳的这本书中也有体现。 维纳不仅强调了法律和语言通信的关系,还以契约法为例指出了法律必须有解释机构。“如果所用术语的意义未经确定或者它们的意义随法庭的不同而不同,则契约的双发就不能以任何正义来弄清订契约的意义了。”。我觉得,既然执行法律被类比为了通信,那么契约法律就类似我们现在常说的通信协议,收发双发事先的一致,才能有效的让有用的信息传递。 维纳还表达了他对当时刑法的不满,他说这是因为有人将刑法看做惩罚罪犯的手段,有人看做赎罪的仪式,有人看做隔离罪犯的手段,还有人看做道德改造的手段。因此,这导致了刑法制定的混乱。 (摘录)因为立法者或法官要对法律作出唯一正确的解释,因此,法律可以看做通信问题或者控制论问题,也就是说,法律的问题就是对若干危险情况进行只需和可重复的控制。 维纳还将当事人力图用法律条文赢得法官和陪审员的支持、律师有意图地引入混乱设法让对方的陈述无效类比为冯诺依曼博弈行为,或者一种互相的信息阻塞行为。 [1] 豆瓣读书–人有人的用处, https://book.douban.com/subject/1455960/