和reeze聊天,reeze问我:linus搞出了linux和git。。你呢?将要怎么样改变世界?
到此,忽然思维停住了。我呢?我是谁?我在哪?我在做什么?我将要怎样改变世界?
很想哭的,那种眼睛涩涩的感觉。
我们在为生活奔波,当年的理想,曾经的誓言,已经不知去了何处。
……
……
只为记录。
和reeze聊天,reeze问我:linus搞出了linux和git。。你呢?将要怎么样改变世界?
到此,忽然思维停住了。我呢?我是谁?我在哪?我在做什么?我将要怎样改变世界?
很想哭的,那种眼睛涩涩的感觉。
我们在为生活奔波,当年的理想,曾经的誓言,已经不知去了何处。
……
……
只为记录。
买《程序员的思维修炼-开发认知潜能的九堂课》这本书有一段时间了,到今天才看完,薄薄的一本书,值得细细品味。很久没有写读书笔记了,本书中建议读完一本书后就应该写一篇总结或至少认真写个评论,阅读更多的书,就会有更多的东西可以写。
这是一本包含了认知科学、神经学、学习和行为理论,以程序员更能理解的形式介绍了人类大脑的工作机制,并研究如何克服这个系统的局限来提高自己学习和思考的技能。
其中一些观点印象深刻。
最开始是关于技能获取领域的德雷福斯模型(Drefus model)。此模型是一个针对每项技能的的评估体系,它能表示你处于某个特定技能领域中的某个水平阶段。如PHP开发新手、linux专家等。它分为五个等级:新手、高级新手、胜任者、精通者、专家。新手依赖于规则,规则可以让他们开始工作。他们拥有对此领域极少的技能或根本没有技能。新手非常在乎最后的结果,希望自己做的东西能取得明显的效果,当一个功能做出来后,就会有非常大的成功感,会觉得自己是人才。但是由于他们经验的缺失,不知道如何应对出现的错误,此时可能会不知所措。
与新手相比,高级新手已经有一些经验,能够根据一些总体的原则,尝试着解决问题,但是他们没有一个对此领域的全局的理解,并且也不会想去了解,无法站在一个更高的高度去理解现在看到的内容。
胜任者在团队中往往发挥着领导作用,能够独立的解决问题,有时也可以指导新手处理问题。他们往往具有良好的主动性,他们的工作依赖于自己以往的经验,开始学会寻找新的问题的解决方案,如寻求专家的帮助、google等。但是他们缺少对于自身错误的反思和纠错能力。
精通者更多的表现在能时常反思,时常纠错。他们有足够的经验,知道下一步会发生什么,知道如何应对即将发生的事。这个阶段的程序员往往能正确应用设计模式。
专家根据直觉工作,不需要太多理由。他们总在寻找更好的方法和方式,他们有丰富的经验,他们擅长布道。
在现实中,大多数人都是高级新手,他们不知道自己不知道。
我们需要勇于承担责任,保持实践以维持专家技能(如果你是一个leader,也不要脱离开发第一线),多考虑情境,培养更多的直觉。
我们的大脑的配置是双CPU,单主机总线设计。1号CPU负责线性、逻辑思维和语言处理,处理速度较慢,我们称之为L模式;2号CPU不做任何语言处理,当你“思考”时,它会去搜索和匹配,异步返回结果,我们称之为R模式。R型对直觉、问题解决和创造性非常重要。
基于R的不可预测性,我们需要建立外部存储设备,如记事本、PDA等等,当有想法时记录下来,每个人都有好点子,但只有少数人会努力付诸实际先去,只有更少的人将这些好点子成功实现。
如果想成为专家,需要更多的启动你的R型CPU,作家中流传一句话:酒醉写作、酒醒修改,程序员中的结对编程模型都是L和R型充分利用的例子。利用图像、晨写技术、写博客、散步等方式可以让你大脑中的R型自由展示。
程序有BUG,而我们的大脑也会有许多出错的地方,这些错误会影响我们的思维。书的作者介绍了4大类问题:认知偏见、时代影响、人性倾向和硬件故障。
我们常见的认知偏见有思维定势、基本归因错误、自私的偏见、需要定论、认可上的偏见、曝光效应、霍桑效应、虚假记忆、符号约简谬论等。
我们渴望知道结果,从而我们总是努力消除不确定性,但过早的下结论会减少我们的选择。因此我们需要顶住压力,推迟下结论的时间。我们的记忆并不靠谱,甚至会有虚假记忆,用笔或类似的方式记录下你需要记忆的信息,我们需要一些东西来确保你的记忆不会与事实想去甚远。
偏见会随着时间改变,我们都是时代的产物,在不同的时代之间存在着我们常说的代沟。除了时代的影响,我们的个性会影响我们的价值观和看法。性格和技能水平不同,其奖励的方式也应该不同。尊重不同人的不同性格,不要试图改变别人的性格以适应自己。
技术本身并不重要,持续学习才是最重要的。教育字面的意思却是“被引出”。建立SMART任务实现你的目标。我们需要记住:时间是无法创造和销毁的。时间只能分配。教是最好的学。
放松以集中注意力,我们开发外部信息处理系统,以浸泡、分类和发展想法。
优化当前情境,减少情境切换,因为平均需要20分钟才能返回到原来的工作状态,从而不要时不时的检查邮件,避免分心,定制单任务界面。
认识你自己,认识当前时刻,认识你所处的情境。从现在开始改变,虽然开始很难,困难很多,甚至反复,坚持。
锁机制之所以存在是因为并发导致的资源竞争,为了确保操作的有效性和完整性,可以通过锁机制将并发状态转换成串行状态。作为锁机制中的一种,PHP的文件锁也是为了应对资源竞争。假设一个应用场景,在存在较大并发的情况下,通过fwrite向文件尾部多次有序的写入数据,不加锁的情况下会发生什么?多次有序的写入操作相当于一个事务,我们此时需要保证这个事务的完整性。
如下代码简单模拟了这种事务并发状态: process1.php
<?php
$num = 100;
$filename = "processdata.txt";
$fp = fopen($filename, "a");
for ($i = 0; $i < $num; $i++) {
fwrite($fp, "process1: " . $i . "\r\n");
usleep(100000);
}
fclose($fp);
?> |
我们需要先执行第一个事务,在processdata.txt文件中写入这100行。
process2.php
<?php $num = 100; $filename = "processdata.txt"; $fp = fopen($filename, "a"); for ($i = 0; $i < $num; $i++) { fwrite($fp, "process2: " . $i . "\r\n"); usleep(100000); } fclose($fp); ?> |
第二个事务,继续向processdata.txt文件中写入100行。
多次同时执行,虽然都写了100行,但是事务1和事务2的数据交错写入,这并不是我们想要的结果。我们要的是事务完整的执行,此时我们需要有个机制去保证在第一个事务执行完后再执行第二个。在PHP中,flock函数完成了这一使命。在事物1和事务2的循环前面都加上: flock($fp, LOCK_EX); 就能满足我们的需求,将两个事务串行。
当某一个事务执行完flock时,因为我们在这里添加的是LOCK_EX(独占锁定),所以所有对资源的操作都会被阻塞,只有当事务执行完成后,后面的事务才会执行。我们可以通过输出当前的时间的方法来确认这一点。
关于在尾部追加写入,在unix系统的早期版本中存在一个并发写入的问题,如果要在尾部追加,需要先lseek位置,再write。当多个进程同时操作时,会因为并发导致的覆盖写入的问题,即两个进程同时获取尾部的偏移后,先后执行write操作,后面的操作会将前面的操作覆盖。这个问题在后面以添加打开时的O_APPEND操作而得到解决,它将查找和写入操作变成了一个原子操作。
在PHP的fopen函数的实现中,如果我们使用a参数在文件的尾部追加内容,其调用open函数中oflag参数为 O_CREAT|O_APPEND,即我们使用追加操作不用担心并发追加写入的问题。
在PHP的session默认存储实现中也用到了flock文件锁,当session开始时就调用PS_READ_FUNC,且以O_CREAT | O_RDWR | O_BINARY 打开session数据文件,此时会调用flock加上写锁,如果此时有其它进程访问此文件(即同一用户再次发起对当前文件的请求),就会显示页面加载中,进程被阻塞了。加写锁其出发点是为了保证此次会话中对session的操作事务能完整的执行,防止其它进程的干扰,保证数据的一致性。如果一个页面没有session修改操作,可以尽早的调用session_write_close()释放锁。
文件锁是针对文件的锁,除了这种释义,还可以理解为用文件作为锁。在实际工作中,有时为确保单个进程的执行,我们会在程序执行前判断文件是否存在,如果不存在则创建一个空文件,在进程结束后删除这个空文件,如果存在,则不执行。