枪炮、病菌与钢铁

《枪炮、病菌与钢铁》

作者 贾雷德·戴蒙德

致我的中国读者

物理学家、化学家和分子生物学家告诉我们,唯一严谨的科学研究方法是进行可操纵的实验室实验

开场白 亚力的问题

几乎所有的儿童发展都强调:童年的刺激和活动有助于心智发展,不可逆的心智障碍与童年时的刺激不足有关。

各族群的历史循着不同的轨迹开展,那是环境而非生物差异造成的。

世界技术发展的共通模式反倒更容易理解。食物生产手段让农民生产出食物盈余,因此农业社会可以供养全职的技术专家,他们不用亲自耕作,只要专注于发展技术。

第一部分 从伊甸园到卡哈马卡

第一批走出非洲的人类祖先是直立人,其化石证据是在东南亚的爪哇岛发现的“爪哇人”(Java man)。

今天西伯利亚与阿拉斯加之间浅浅的白令海峡在冰期由于海面的升降,有时是海峡,有时则是宽广的洲际陆桥。

第2章 历史的自然实验

一般而言,政治单元越大,人口密度越高,技术和组织就越繁复

人口密度与政治单元大小的差异对波利尼西亚各地的社会有何影响?经济生活仍非常简单的岛屿要么人口密度低(如查塔姆群岛上的狩猎—采集社群),要么人口数量少(小环礁上的社群),要么二者皆是。在这种社会,家家户户自给自足,经济上几乎不需要专业分工。经济专业化是在面积较大、人口密度较高的岛屿发展出来的

第3章 卡哈马卡的冲突

阿塔瓦尔帕的被俘是现代历史上最大冲突中的决定性时刻,因此令人玩味不已。但这一事件之所以能引起更广泛的关注,是因为使得皮萨罗虏获阿塔瓦尔帕的种种因素,也在现代世界中许多殖民者和土著的冲突中起了作用。可以说,阿塔瓦尔帕被俘为我们了解世界史打开了一扇窗。

皮萨罗的武力优势在于西班牙人的枪炮、刀剑和马匹。而阿塔瓦尔帕的军队作战时没有骑乘任何动物,武器也只有石头、铜器、木棒、狼牙棒、斧头,加上弹弓和其他拼凑起来的武器。这种悬殊决定了美洲土著等族群与欧洲人交锋时的命运。

阿塔瓦尔帕之后成为印加皇帝的曼科(Manco),其麾下最骁勇善战的是尤潘基(Quizo Yupanqui)。1536年,尤潘基率军在利马发动突袭攻打西班牙人,然而对方只派出两支西班牙骑兵就把他们打得落花流水,尤潘基和手下的将领都被杀,全军覆没。另一支26名骑兵组成的队伍则在库斯科击败了曼科亲率的精锐。

较有免疫力的入侵族群把传染病带给其他没有免疫力的族群。天花、麻疹、流感、斑疹伤寒、腺鼠疫等已在欧洲蔓延的传染病,反倒成了欧洲人征服世界各地族群的助力。

皮萨罗成功的直接原因包括基于枪炮、钢铁武器和马匹的军事技术,来自欧亚大陆的传染病,欧洲的海事技术,中央集权的政治组织,以及文字。

第二部分 食物生产的兴起与扩散

食物生产对枪炮、病菌和钢铁的发展而言,是间接的前提条件。因此,从各大洲族群从事农牧的地理条件可看出日后的命运。

通过驯化动植物比狩猎—采集方式产出更多食物,从而增加人口密度,这是作物和家畜对人口直接的影响。间接一些的影响,是此类食物生产方法需要人们定居下来,这种生活方式促成了人口密度的增加。

作物和牲畜的有无,从根本上解释了为何帝国、文字、钢铁武器最早在欧亚大陆出现,而在其他地方较晚甚至没有出现。

第5章 历史上的有与无

所有生物体内的碳元素中,都含有固定比例的放射性碳14原子。生物死亡后,就不再从外界吸收碳元素,体内已有的放射性碳14原子仍继续衰变,半衰期约5 700年,生物死后大约4万年,其体内碳14的量就低到难以测量,或者难以和晚近时期混入的少量含碳14的遗存分辨了。

利用碳14测年法的第二个问题,就是大气中碳14与碳12的比例实际上并不恒定,而是在不同的时间段内有波动,因此基于比例恒定假设的计算结果必然存在系统性的小误差,必须加以校正。

在有些地区,生产食物的手段完全是独立发展出来的。这些地区在外来作物与动物输入之前,自行驯化了很多本土的作物与动物。这种地区目前只有5个我们有翔实的证据:西南亚(或称近东或肥沃新月地带)、中国、中美洲(墨西哥中部、南部以及邻近的中美洲地区)、南美洲的安第斯山脉(或许还包括邻近的亚马孙盆地)和美国东部

食物生产方面取得先机的族群,在迈向枪炮、病菌和钢铁的路途上,领先群雄。其结果就是历史上一连串“有”与“无”的冲突。

第6章 下田好,还是打猎好?

人类最近1万年的历史彰彰在目的事实,就是人类生计的变迁,主流是从狩猎—采集转变成食物生产。因此我们必须问的是:哪些因素让食物生产显得有利,使其他的生计类型都失色了?

第一个因素是可获得的野生食物越来越少。

第二个因素是,随着可驯化的野生植物变多,驯化植物的回报越来越多

影响狩猎—采集和农业消长的第三个因素,是生产食物的技术(例如采收、处理和储藏)不断改进。

第四个因素是人口密度上升与食物生产兴起的双向关联。

接受食物生产是一种自催化的过程,也就是在一个正回馈循环中不断自我催化的过程,这个过程开启后就会加速。

明白了食物生产与人口密度的这种双向关联,就可以解释这样一种矛盾状况:食物生产增加了每英亩土地上可食用卡路里的数量,但食物生产者的营养状况不如被他们取代的狩猎—采集者。之所以有时会出现这种状况,是因为食物增产的速度稍稍落后于人口增加的速度。

食物生产者社群的人口密度很高,凭数量优势就足以驱逐或消灭狩猎—采集者,更别提其他优势了(包括技术、病菌和职业军人)。

只有当地理或生态屏障将食物生产者拦在外面,或使得适用于当地的食物生产技术难以传入的时候,狩猎—采集者才有可能一直到近现代都在适于农牧的土地上保持原有的生活方式。

第7章 杏仁的前世今生

这些作物多半是自花传粉,直接把有利的基因传给下一代,不必和其他较没有价值的植物杂交,坏了自己的种。

谷物和豆类相比,这些作物的缺点是至少得种植3年才可能有收成,盛产期则必须等待10年之久。因此,只有在一地长住的人才有可能种植这些作物。这些最早的果树和坚果树还容易栽种,插枝甚至撒下种子就长出来了,晚期才被驯化的树木可没这么简单。插枝还有个好处,也就是保证后代和亲代一模一样。

谷物的优点有长得快、碳水化合物含量高,每公顷可收获多达1吨的食物。因此,谷物在今天人类摄入的卡路里中占了超过半数。今日世界的12种主要作物中,谷物就有5种:小麦、玉米、稻米、大麦和高粱。很多谷物蛋白质含量低,但这种缺陷可由豆类来补足。豆类的25%是蛋白质,黄豆更高达38%,谷物和豆类是均衡饮食不可或缺的。

第8章 是苹果的问题,还是印第安人的问题?

现代世界作物年产量的80%是由十几种植物贡献的。这十几种“重量级”的作物如下:谷物有小麦、玉米、稻米、大麦和高粱,豆类有黄豆,块根或块茎类为马铃薯、木薯、甘薯,糖分的来源则是甘蔗、甜菜,水果如香蕉。

小麦、大麦的天生优势和墨西哥类蜀黍的明显劣势,大概就是欧亚社会和新大陆社会发展差异的要因。

肥沃新月地带的第三大优势,就是雌雄同株自花传粉的植物比例很高,这些植物偶尔也行异花传粉。

大多数的野生植物是雌雄同株异花传粉,或是雌雄异株——这种生殖生物学的现象给早期农民添了很多麻烦,因为他们选择一种突变的植物栽种后,其子代往往因和其他植株杂交而失去原来的特色。因此,大部分的作物来自野生植物中小部分行雌雄同株自花传粉者,或经无性生殖产生者(如用根来种植以复制亲代基因)。

野生单粒小麦、二粒小麦和大麦这三种的蛋白质含量很高,为8%~14%,相形之下,东亚的首要作物稻米和新大陆的玉米则蛋白质含量少,营养问题比较严重。

农业最早在肥沃新月地带发端,主要是“八大始祖作物”之功,它们是属于谷物的二粒小麦、野生单粒小麦、大麦,属于豆类的兵豆、豌豆、鹰嘴豆、苦野豌豆,属于纤维作物的亚麻。在这八种作物之中,只有亚麻和大麦的野生种分布超出了肥沃新月地带和安纳托利亚地区;有两种始祖作物的分布范围很窄,鹰嘴豆只在土耳其东南部,二粒小麦的分布范围则限于肥沃新月地带。因此,肥沃新月地带驯化当地现成的野生植物就足以发展农业,无须仰赖外地引入的作物包。有两种始祖作物无法在肥沃新月地带以外的地方被驯化,主要原因是它们只在肥沃新月地带有。

在食物生产兴起前,人类大抵以野生物种为食,因此掌握的关于野生动植物的知识特别丰富。最早的农民承袭了这样的知识——几千年来和大自然亲密生活、观察而累积下来的经验。因此,有价值的物种似乎不大可能逃过早期农民的眼睛。

其他领域也是一样的道理

能优先获得引进的新作物和家畜(或者在文化上乐意接受新作物和家畜)的族群就可扩张版图,没有门路或意愿接受的族群自然遭到淘汰。

肥沃新月地带登峰造极,新几内亚和美国东部则乏善可陈。肥沃新月地带野生动植物的驯养可谓轻而易举,不但驯化了许多物种,其中品种多产而优良者比比皆是,而且种类繁多。结果得以发展出精密的粮食生产业,促使人口更加稠密,进而迈入有先进技术和复杂政治组织的现代世界,同时携带可以消灭其他族群的传染病。

事实上,这个地表的各大洲上有成百上千互相竞争的社会,有些比较开放,很能接受新事物,有些则趋向保守。接受新的作物、家畜和技术的,就能日益精进,领袖群伦,人口数目远远超过那些不愿接受新事物的族群,接着便向后者大举入侵,甚至将之连根拔起。

Linux 进程调度

总体来说,调度主要解决两类问题:

  • 什么时候调度
  • 调度的目标是谁 而一个优秀的调度系统,可以从如下几个指标判断:
  • fast process response time
  • good throughput for background jobs
  • avoidance of process starvation
  • reconciliation of the needs of low- and high- priority processes

Linux调度基于分时(Time-Sharing):多个进程共享同一个CPU,CPU运行时切分成多个时间片。分时技术依赖于timer interrupt,对进程来说是透明的。

Linux进程是可抢占的。当进程切换到TASK_RUNNING状态,内核检查其动态优先级是否比当前运行的进程的优先级高。如果更高,当前执行的进程中断掉,调度器切入,选择另外一个进程运行(通常是刚刚切换成runnable的进程)。当进程的时间片消耗完毕时,进程也是可被抢占的。当前进程struct thread_info中的TIF_NEED_RESCHED被设置,timer interrupt handler终止后,scheduler切入。

一个被抢占的进程并不是被暂停,它还维持在TASK_RUNNING状态,只不过不再使用CPU。

调度算法

Linux 2.6版本之前的调度算法很简单,进程切换时,内核扫描runnable进程列表,计算它们的优先级,选择“最优”的进程运行。这种算法的问题是切换时的时间开销会随着进程数目的增多呈线性增长。

调度策略:

  • SCHED_FIFO
  • SCHED_RR
  • SCHED_NORMAL

O(1) Scheduler

基于Linux-2.6.12版本。

优先级

Linux 2.6.12 内核里,优先级表示分为用户态和内核态。用户态优先级就是我们常用的nice值。取值范围[-20, 19]。内核态优先级被称作静态优先级(static priority),取值范围是[0, 139]。其中,[0, 99]是Real-Time Process,[100, 139]对应用户态nice值。

在静态优先级外,真正发挥作用的是动态优先级(dynamic priority)。动态优先级实际上是静态优先级加上了一个运行时补偿(bonus): $$ dynamic_priority = max(100, min((static_priority - 5 + bonus), 139)), bonus \in [0, 10] $$

Linux 进程

进程和轻量级进程

image-20211112165309944

在Linux内核中,进程/线程对应的数据结构是task_struct,定义在include/linux/sched.h中。

线程在Linux中的实现是 Naive POSIX Thread Library 。在内核眼中,Linux的线程实际上也是一个进程(task_struct),区别是线程的“进程”共享了地址空间、文件描述符等,称作==轻量级进程==。因此,Linux的线程也是独立的调度单元,是可以分别在不同的CPU上同时运行的。原生的Linux 线程(2.6版本内核之前)因为只实现在了用户态,所以,即使是一个多线程程序,对于内核来说只能看到一个进程,这些线程就只能在一个CPU上运行,对于多核多线程来说是很致命的。

从实现的角度,Linux的线程(LWP)是通过pthread库创建/使用的。而进程和线程的创建都调用了clone()系统调用(kernel/fork.c )。区别是两者使用了不同的flags。

进程管理

进程状态

  • TASK_RUNNING: The process is either executing on a CPU or waiting to be executed
  • TASK_INTERRUPTIBLE: The process is suspended (sleeping) until some condition becomes true.
  • TASK_UNINTERRUPTIBLE: Like TASK_INTERRUPTIBLE, except that delivering a signal to the sleeping process leaves its state unchanged.

PID

PID用来区分不同的进程结构体。Linux中最大PID数目可以在/proc/sys/kernel/pid_max中查看。

每个进程/轻量级进程都分配有一个唯一的PID。但是对于同一进程中的线程来说,我们拿到的是进程ID确是相同的,这是怎么实现的呢?

Linux为了兼容POSIX标准,利用了线程组(thread group)这一概念。所有的线程都会把线程组里面第一个线程的PID存在tgid字段内。==getpid()系统调用返回的实际上是tgid的值。==

/**
 * sys_getpid - return the thread group id of the current process
 *
 * Note, despite the name, this returns the tgid not the pid.  The tgid and
 * the pid are identical unless CLONE_THREAD was specified on clone() in
 * which case the tgid is the same in all threads of the same group.
 *
 * This is SMP safe as current->tgid does not change.
 */
SYSCALL_DEFINE0(getpid)
{
    return task_tgid_vnr(current);
}

bitmap管理PID

IDR管理PID

  • PID: replace pid bitmap implementation with IDR API commit, commit

进程切换

==TLDR:进程在调用schedule()方法时,将当前进程运行的寄存器信息保存在task_struct->thread_info内,同时从进程B中的task_struct->thread_info中加载B运行时的寄存器信息。==

正念冥想

正念是什么

与事物的现实性达成一致,我们可以通过拥抱它们来接受它们,在一刻一刻的觉知里。

正念不是一个概念,而是一种与生命保持明智关系的方式,在生命唯一的当下展开。

正念的态度因素

如果想要长期地实践正念,并将正念融入到生活当中,那么我们需要关注一些正念的态度因素。对于这些正念的态度因素,最主要的是让这些概念融入到脑内,心里,而并非是强制遵守它。记住即可。

不做评判

不做评判并不意味着我们不去对事件品头论足,而是说==意识到在做评判,并且有目的地不陷入到评判中,这本身就是一种美丽而又温柔的修习。==从某种意义上来说,这种修习的目的是让我们==足够关心自己以及我们所处的环境,从而不会有那种瞬间崩溃,也不会拘泥于喜欢或者不喜欢,想要或者不想要。==归根结底,当我们做出一个评判时,实际上我们就成为了它的囚徒。因为当事情发生时,评判降低了我们应对挑战的可能性。我们会困在一个观点中,而这个观点可能并不是一个完整地故事,完整地视角(盲人摸象)。

==关键点:不被自己地喜欢和厌恶所禁锢。把自己从下意识去评判“好”与“恶”这个习惯中解救出来,从自己的欲望和恐惧中解救出来。==

耐心

当我们失去耐心时,受害者往往是与我们生活在一起的人,我们最爱的人,还有和我们一起工作的人。

我们都希望朝着一个真正变化的、有益的方向前进。但如禅语所说,==“you can’t push the river”==,不能逆势而为。为了到达某个地方而逼自己加快脚步是不明智的,因为这样往往会让自己忘记了真正的目的。

耐心是我们可以培养的一种非常可贵的品质。特别是在我们当下这个时代,它显得愈发重要。在这个电子信息时代,我们被电子产品吸引,甚至对其上瘾。我们的社会变成了一个点击型社会,所有在手机或者电脑上呈现的东西,逐步变得愈来愈“快餐”和“标题党”。它们通过社交媒体分发给我们,给我们想要的东西。这些“快餐”或者朋友圈的“点赞”实际上触发了我们大脑中神经元的连接,刺激多巴胺的释放,在这一瞬间会给人你一种非常非常满足的感觉。我们会因为朋友圈的一个“点赞”获得极大的满足感,但是这只持续了不到一秒,然后呢?我们会想要更多。我们开始观察社交媒体的生态,然后变得愈发不耐烦,这就是上瘾的一种表现,而我们甚至对此都毫无觉察。

所以耐心实际上培养了对这种事情的免疫力。因为当我们意识到有那种想要得到什么的冲动时,我们可以让自己慢下来(延迟满足)。==所以在一整天里,不断地觉察到自己有多么不耐烦,这便能帮助我们培养耐心。==

我们不必强迫自己变得耐心,而是去关注那些真的陷进去的时刻,强烈地想要去得到某个结果,然后引发出一系列蝴蝶效应般的结果,最后我们再也无法被满足(成瘾)。

初学者心态

In the beginner’s mind there are many possibilities, in the expert’s mind, there are few.

—— Suzuki Roshi(铃木俊隆)

==在某种意义上,我们所知道地一切都会妨碍我们看到那里的一些东西。因为我们是在透过我们的有色眼镜看面前的东西。==原有的知识结构,可能会演变为严重的问题。因为它会限定你,让你在已知的领域中对那些新兴未知的苗头视而不见,而那才是你想要发现的,全新的,前所未见的东西。

信任

将信任带入修习实际上是在提醒自己有很多我们可以信任的东西,就比如我们可以相信我们的呼吸正在i体内穿梭,我们的脚将带着我们前行,我们的心脏仍会在今晚继续跳动。这些都是在提醒我们在当下这个时刻发生的事情中,有多少是可信的,是真正值得信任的。 最重要的是,我们的心是否值得信赖。==唯一能让自己的新值得信赖的方法就是相信自己,相信自己值得信赖,即便是我们把注意力放在了可能辜负自己或者他人信任的事情上==。

信任是深刻的,象征洞察力的源泉。它包括如何将内在与外在的经历发散开,使其保持良好的关联。

不争

不争不是反对积极。**不争可能会要你去做更多的事情——不依附于结果,不去拼命让结果显得更好,而是确保当下正在做的每一件都具有完整性,然后水到渠成。**现实中我们会有DDL,会有一些杂七杂八的事情,看起来和不争的概念相悖。但是当把不争带到我们的意识前,让我们专注于当下,实际上可以帮助我们更快地完成工作。

当你的目标非常明确的时候,不争是很有效的。当我们太执着于胜利的结果时,可能会得不到很好的结果,因为心浮气躁。不争是将我们对胜利的渴望剥离出来,这并不意味着我们会成为一个消极的人,总是一事无成。

接纳

接纳意味着看到事物的现实,承认并接受它们就是这样的。 接纳并不意味着我们不能努力去改变它们,接纳意味着看清现实,意味着你有时会意识到一些不可接受的事情。然后的问题是,我们该如何与这些不可容忍的事情,需要改变的事情保持明智的关系?这和消极的顺从一点关系都没有。

==我们需要看到真实的现实,正在发生的一切,看到它的复杂性以及简洁性。看得清楚,然后开始行动。接纳意味着对事物的现状有深刻洞察的认识,如果你是唯一一个看清这件事情走向的人,相信自己。==

Go channel 实现

Go的Channel在runtime里面是一个hchan的结构体,每次我们make一个新的channel时,runtime从heap内分配一个hchan结构体管理channel。

type hchan struct {
    qcount   uint           // total data in the queue
    dataqsiz uint           // size of the circular queue
    buf      unsafe.Pointer // points to an array of dataqsiz elements
    elemsize uint16
    closed   uint32
    elemtype *_type // element type
    sendx    uint   // send index
    recvx    uint   // receive index
    recvq    waitq  // list of recv waiters
    sendq    waitq  // list of send waiters

    // lock protects all fields in hchan, as well as several
    // fields in sudogs blocked on this channel.
    //
    // Do not change another G's status while holding this lock
    // (in particular, do not ready a G), as this can deadlock
    // with stack shrinking.
    lock mutex
}
  • qcount:当前channel queue内的element数目,当qcount等于dataqsiz时,表示channel buffer已经满了,send channel会被阻塞;
  • dataqsiz:channel的buffer大小,也就是我们在make时设定的值。dataqsiz在channel创建后不会再变动,因此channel的buffer是不会动态扩容的;
  • buf:buffered channel缓存elements的内存地址。是一个数组实现的环形队列;
  • elemsize:element类型大小;
  • closed:channel是否已经被关闭,防止关闭已经关闭的channel;
  • elemtype:channel element 类型;
  • sendx:buffer中下一个生产的element的index;
  • recvx:buffer中下一个消费的element的index;
  • recvq:阻塞的接收channel,是一个sudog的链表
  • sendq:阻塞的发送channel,是一个sudog的链表

当buffer没有满时,send channel发送elements时直接把elements放在buf内,增加sendx和qcount;当buffer满时,send channel被阻塞,并加入到sendq链表内,等待被唤醒;