学校不教的计算机课

最近HN上有一篇讨论较火的文章Computer Science Courses that Don’t Exist, But Should,翻译了一下。注意,这篇文章首先发布在csdn,禁止任何形式的转载。

CSCI 2100:忘掉面向对象编程

思考如何创建、使用不属于任何对象的变量。学习“函数(functions)”,它跟方法(methods)很像但是更有用的多。前提是你已经学过一门使用了“抽象基类的课程”。

CSCI 3300:像经典软件学习

讨论并剖析具有划时代意义的软件产品,比如VisiCalc、AppleWorks、Robot Odyssey、Zork、和MacPaint等。学习的重点,在于用户界面,以及由硬件限制激发出的创造力。

CSCI 4020:用低效语言编写高效代码

对性能进行深度分析,用解释型的Python语言来写出能与传统的编译型C++匹敌的代码。而且代码还会更加健壮,写起来也很有意思。

CSCI 2170:用户体验之”命令行工具”

提高用户体验的原则也同样适用于命令行工具的设计,要专注于输出信息的相关性,可读性,最简化。UNIX的“ls”命令就是值得好好学习的一个例子。

PSYC 4410(心理学高年级课程):程序员内心强迫症

能辨别和理解那些无关紧要,但是程序员偏偏会去较真的事情:代码格式、如何分类、类型系统,非要将项目分解成很多个。还包括接触到不熟悉的系统时下意识的批评的细节。


HN精彩评论

  • 我能再加一个吗?“网络不像你想的那么简单:分布式系统生存指南”。作为一个在职业生涯中花了很多精力建设高性能网络,也和这个领域里地人公事了很长时间的一个程序员来说,我对现在从名校毕业的学生在这方面的知识之匮乏感到震惊。很多基本的东西,像是应用的无线传输,系统如何处理数据包,等待对应用的影响等等,对于一些程序员来说简直一窍不通。现在看来,网络连接的实质问题,确实被严重忽略了。
  • 程序员分为两种:一种被训练成能在熟悉的环境中称职地编码;另一种则像是《黑客帝国》中选择了红色药丸的人——他们知道事物的本质。
  • 再加一些:
    • 在白板上写翻转二叉树
    • 用COBOL实现Monads
    • 如何正确地纠正网络上的评论
    • 上一条中的槽点可能有哪些
    • 对Twitter的多项式机器人算法有多糟糕的介绍
    • 用Haskell学习函数式编程
    • 上一门课的实际用途
  • 亲爱的机算计学院:请不要再拿“算法导论”课来愚弄你们的学生了,这门课应该改为“组合算法导论”,因为这才是你们教的东西。你们完全忽视了“数字算法”,这是许多其他计算机学科分支的基础(计算机物理、计算机化学、计算机生物学等),同时这也是机器学习和数据科学毕业生薄弱之处。或者也可以保留“算法导论”的名字,但是教50%的算法和数据结构,50%的数字计算方法和科学计算。
  • “建立端对端软件解决方案”如何?让这门课贯穿所有软件开发流程(想法-设计-原型-公测-发布-迭代)。我最好的朋友马上毕业了,可他对软件开发一无所知,根本不了解现在的市场需求。
  • “Debug”:严肃地讲,这是门完整、系统的课程,而且越早开设越好。这是其他学科/工程不可缺少的技能。
  • 计算机科学和软件工程应该分成两门完全不同的学科。
 

垃圾回收(GC)的三种基本方式

垃圾(Garbage)就是程序需要回收的对象,如果一个对象不在被直接或间接地引用,那么这个对象就成为了「垃圾」,它占用的内存需要及时地释放,否则就会引起「内存泄露」。有些语言需要程序员来手动释放内存(回收垃圾),有些语言有垃圾回收机制(GC)。本文就来讨论GC实现的三种基本方式。

其实这三种方式也可以大体归为两类:跟踪回收,引用计数。美国IBM的沃森研究中心David F.Bacon等人发布的「垃圾回收统一理论」一文阐述了一个理论:任何垃圾回收的思路,无非以上两种的组合,其中一种的改善和进步,必然伴随着另一种的改善和进步。

跟踪回收

跟踪回收的方式独立于程序,定期运行来检查垃圾,需要较长时间的中断。

标记清除

标记清除的方式需要对程序的对象进行两次扫描,第一次从根(Root)开始扫描,被根引用了的对象标记为不是垃圾,不是垃圾的对象引用的对象同样标记为不是垃圾,以此递归。所有不是垃圾的对象的引用都扫描完了之后。就进行第二次扫描,第一次扫描中没有得到标记的对象就是垃圾了,对此进行回收。

复制收集

复制收集的方式只需要对对象进行一次扫描。准备一个「新的空间」,从根开始,对对象进行扫,如果存在对这个对象的引用,就把它复制到「新空间中」。一次扫描结束之后,所有存在于「新空间」的对象就是所有的非垃圾对象。

这两种方式各有千秋,标记清除的方式节省内存但是两次扫描需要更多的时间,对于垃圾比例较小的情况占优势。复制收集更快速但是需要额外开辟一块用来复制的内存,对垃圾比例较大的情况占优势。特别的,复制收集有「局部性」的优点。

在复制收集的过程中,会按照对象被引用的顺序将对象复制到新空间中。于是,关系较近的对象被放在距离较近的内存空间的可能性会提高,这叫做局部性。局部性高的情况下,内存缓存会更有效地运作,程序的性能会提高。

对于标记清除,有一种标记-压缩算法的衍生算法:

对于压缩阶段,它的工作就是移动所有的可达对象到堆内存的同一个区域中,使他们紧凑的排列在一起,从而将所有非可达对象释放出来的空闲内存都集中在一起,通过这样的方式来达到减少内存碎片的目的。

引用计数

引用计数是指,针对每一个对象,保存一个对该对象的引用计数,该对象的引用增加,则相应的引用计数增加。如果对象的引用计数为零,则回收该对象。

优点:引用计数最大的优点就是容易实现,C++程序员应该都实现过类似的机制。二是成本小,基本上引用计数为0的时候垃圾会被立即回收,而其他方法难以预测对象的生命周期,垃圾存在的时间都会比这个方法高。另,这种垃圾回收方式产生的中断时间最短。

缺点:最著名的缺点就是如果对象中存在循环引用,就无法被回收。例如,下面三个对象互相引用,但是不存在从根(Root)指向的引用,所以已经是垃圾了。但是引用计数不为0.

DC_counter_way

还有一个缺点就是,引用计数不适合在并行中使用,多个线程同时操作引用计数,会引起数值不一样的问题从而导致内存错误。所以引用计数必须采用独占方式,如果引用操作频繁,那么加锁等并发控制机制的开销是相当大的。

Perl和Python采用了这种GC机制。

它们的衍生算法

分代回收

这种回收方式用了程序的一种特性:大部分对象会从产生开始在很短的时间内变成垃圾,而存在的很长时间的对象往往都有较长的生命周期。高频对新生成的对象进行回收,称为「小回收」,低频对所有对象回收,称为「大回收」。每一次「小回收」过后,就把存活下来的对象归为「老生代」,「小回收」的时候,遇到老生代直接跳过。大多数分代回收算法都采用的「复制收集」方法,因为小回收中垃圾的比例较大。

这种方式存在一个问题:如果在某个新生代的对象中,存在「老生代」的对象对它的引用,它就不是垃圾了,那么怎么制止「小回收」对其回收呢?这里用到了一中叫做写屏障的方式。

程序对所有涉及修改对象内容的地方进行保护,被称为「写屏障」(Write Barrier)。写屏障不仅用于分代回收,也用于其他GC算法中。

在此算法的表现是,用一个记录集来记录从新生代到老生代的引用。如果有两个对象A和B,当对A的对象内容进行修改并加入B的引用时,如果①A是「老生代」②B是「新生代」。则将这个引用加入到记录集中。「小回收」的时候,因为记录集中有对B的引用,所以B不再是垃圾。

增量回收

上面的算法缩短了「GC平均中断时间」,但是在对实时性要求很高的程序中,对「GC最高中断时间」的要求更高。比如,自动驾驶软件,如果某次GC中断了0.1s,那么损失可能是致命的。

增量回收就是将GC分成几部分来执行。设置「GC最多中断10ms」这样的条件限制来使GC的终端时间视作可预测的。

但是,在两段的GC程序之间,引用关系可能发生了变化。所以,这种GC算法也要写屏障,来记录引用关系的变化。虽然这种方式控制了中断最高时间,但是由于中断次数增加,GC总时间是增加的。

并行回收

基本原理是,在程序运行的同时进行GC工作,最大化CPU的性能。但是这种方式也要面对增量回收的问题,所以也要进行写屏障操作。

然而这种方式也并未做到完全不暂停原程序的运行,在某些特定的GC阶段还是要暂停原程序。多核化迅速发展的今天,这种算法也在不断优化。不间断原程序实现并行回收这个领域是相当值得期待的。

 

在编程中体验纯粹的快乐

Learn Python The Hard Way 的最后,有一个「老程序员的建议」,来告诫学完了这个教程的同学们不要拘泥于编程语言,不要陷入「关于语言的迷信和争吵」中,无论是否从事的是计算机行业,都可以爱上编程,从中的到乐趣。这个老程序员的忠言翻译如下:

现在你已经完成了这个教程,并决定继续深入学习。编程可能成为你的事业,也可能成为你的一个爱好。所以你可能需要一些建议,来保证少走弯路,并从这个「新欢」中的到最大的乐趣。

我从事编程已经很长时间了,长到对我来说这已经是一件极其无聊的工作。我在写这本书的时候,已经懂20门编程语言,能在一天到一个周的时间学会一项新语言(取决于它有多么古怪)。即使这样,我还是对此感到无聊,不再有任何兴趣。但这并不是说编程是很无聊的,也不是说你在将来会觉得它无聊,我意思是,我在干到现在这个年纪,觉得没意思了。

经过这么多年,我发现一个真理:用哪一个编程语言并不重要,重要的是用它来做什么。其实这道理我早就懂,不过还是经常忽视,还是会被编程语言分心。但从现在开始我不会再忘了,你最好也记住。

你学哪门语言,用哪门也都不重要,千万不要陷入对语言的宗教崇拜中,那只会让你忘记原来的目的:把编程语言当做一个工具来做有趣的事情。

编程作为一种智力活动,几乎是唯一一种能创造交互艺术的艺术形式了。你可以写软件让别人来玩,甚至可以通过这种形式直接和别人对话。别的艺术都没有这种交互性。电影拍出来之后直接播放给观众,图画不会动,但是代码能做到。

从事编程行业所获得的乐趣其实一般。这份工作确实不错,但是你可以经营一个快餐店来赚一样多的钱,还更轻松快乐。所以你最好在别的领域将编程作为一个秘密武器。

在科技公司工作的人会编程并没有什么特殊的,也不会获得特殊的尊重。但是从事生物、化学、政治、公务员、社会学、物理、历史和数学的人如果会编程就会格外受到尊重,因为他们能做到这些了不起的事情,来发展他们的学科。

当然了,这些建议都没什么意义。如果你真的喜欢编程,你尝试通过任何方式用它来提高你的生活。尽情去探索这个怪异、神奇、充满智慧的,50年来人们都一直孜孜不倦在探索的世界吧!愿快乐永远与你同在。

最后不得不提的一点,学着写软件可能让你变得有些与众不同。不管是好是坏,总之是不同了。可能有人会对你刻薄,比如在你身上用「书呆子」(nerd)这个词;可能你会发现因为你强大的逻辑,别人都不愿意和你争吵;可能你甚至会发现你懂计算机的运作原理,别人因为觉得你怪异、不合群。

对这些情况我只有一条建议:让他们去死吧!(They can go to hell.)这个世界需要古怪的人,需要书呆子,他们清楚或者热衷于弄清楚事情运作的原理。当真的有人如此对你的时候,要记住:这是你自己的路,不是他们的。与众不同不是犯罪,别人这么说你只是因为他们嫉妒,他们永远不敢在自己的白日梦里奢求这些。

You can code. They cannot. That is pretty damn cool.

 

从《美丽新世界》谈自由

不得不承认,我认为对于人类社会文明的发展来说,《美丽新世界》中描绘的社会的确是一个完美的社会。每一个人都是整体的一部分,极其稳定,人类幸福度高,无忧无虑,安居乐业。但这也是一个及其恐怖的社会。

cover new

在这个完美世界中,「分娩」被认为是淫秽的事情。人类靠试管中的婴儿繁衍后代,「家庭」同样被视为是肮脏的概念,社会中的个人不存在和某个人有特殊的感情。每个男人属于所有的女人,每个女人属于所有的男人。所有的人都可以按照喜好每天选择不同的人性交。每个人都在大剂量的服用性激素和神经类药品(唆麻),一有任何不在「正常范围之内」的小事情就靠药品来逃避。

3fd214221b37441a70a2da45a1a6e041.619x375x1

婴儿还小的时候,育婴室就循环播放录音,达到「洗脑」的效果。例如「母亲是肮脏的」,「历史是废话」,「和家人一起生活将会非常恐怖」等等。书中还提到另一种潜意识的训练——让幼儿去接触鲜花和书籍,然后再给他们电击,以保证他们长大以后不会再碰这些东西。

brave new 1

为了社会稳定,每一个人的个性,感情都被磨灭。个人只是社会的螺丝钉,而社会的等级制度非常森严。从α到ε,分成不同的等级。人们从小的时候就被灌输这种等级制度,在试管里时加入不同的血清使不同等级的人长相区别明显,童年时期穿不同的衣服,玩不同的玩具。这样成年时会有根深蒂固的等级概念。α会觉得自己的工作高雅,看不起ε的体力活。ε会认为自己的工作简单轻松,不像α需要体力劳动。

brave_new_world_social_classes_by_qbark-d4ujz5s

 

这种稳定的社会最怕的就是「个性」。书中说:「文明是绝对不需要高贵行为和英雄主义的。这些事情是政治无能的症状。只有在有战争的时候,英雄主义才会有一点意义。但是现在没有战争,最大的问题就是防止你爱一个人爱的太深。

这个世界看似完美,实际也是。如果这是「文明五」中的一个世界,那么衡量这个社会的所有标准:人口(通过人工繁殖严格控制),经济,科技,幸福度都是无敌的,除了一点——文化。这个社会中人们的娱乐都是「感官刺激」,靠的是唆麻、感观电影。书籍和宗教会让人产生独立于社会体制的思考,所以遭到了根除。但是仔细一想,这样的社会竟然可以正常运作,难道文化在社会中真的没有作用?

不是的。我认为这样的社会完全偏离了方向。社会的终极目标应该是三个哲学问题,如果有重点,那么可能我们最后造出《银河系漫游指南》中的超级计算机来得出答案,可能文化高度发达有人提出并论证了这个答案,可能接触到外星文明,亦或者别的形式的答案。社会总要向着民主,平等的方向发展。文化,是我们存在过的证据,自由和思考,是存在的意义和形式。美丽新世界虽然完美,但这个人们却活的毫无意义。所以书中野蛮人有这样的呐喊:

“可我不想要舒适。我想要上帝,我想要诗歌,我想要真实的危险,我想要自由,我想要善良,我想要罪恶。”

有选择才算是自由,自出生开始被人安排了一切,这和「奴隶制」一样野蛮。世界上不存在不劳而获的幸福,幸福就意味着代价。美丽新世界的幸福,是以牺牲真相为代价的。我宁愿不要这种廉价的幸福,得知真相,痛苦,思考,反省,吸取教训。社会中的每个人都有权利知道真相。这才是自由。

我们现在的科技和网络如此发达,好像我们可以轻易地做自己想做的事情。实则是「美丽新世界」的这种自由。天津爆炸事件之后,大家的焦点仅集中在上面两三天,接着就被娱乐、八卦转移了注意力。相比于独裁政治,这种控制更加可怖。尼尔·波兹曼在《娱乐至死》中一语中的的表达了《美丽新世界》相比于《1984》更加危险:

       在《1984》中,人们受制于痛苦,而在《美丽新世界》中,人们由于享乐失去了自由。奥威尔担心我们憎恨的东西会毁掉我们,而赫胥黎担心的是,我们将毁于我们热爱的东西。

附《娱乐至死》漫画节选p25092201

p25092384

p25092404

p25092448

p25092469

 

p25092483

p25092546

p25092553

 

在快钱实习

下午做完了最后的工作——写文档和注释——在快钱的两个月实习就算是全部结束了。其实这项工作可以从六月算起,那时候虽然还没到公司,但现在看起来,日常基本上和在公司工作的时候是一样的。得到这份实习是因为这个学期的操作系统课(我从小学开始就有特别容易和老师混熟的特异功能),李老师介绍了这份实习。其实一开始,我是拒绝的。因为觉得自己对研发(相对于“开发”来说)性的工作不感兴趣,但是暑假又没有别的计划,于是就去面试了。面试的时候吕博给我介绍了工作内容,欣然接受。于是六月就一边应付考试一边准备工作用到的知识,7月2号考试一结束就去上班了。

工作的内容是“文本挖掘”,需要用到自然语言处理(NLP)和爬虫的知识。说的再简单一些,就是公司有一些消费数据,通过这些数据挖掘到更多的信息,给这些数据加上一些能反映用户的消费倾向的信息,进而可以制作用户画像,再进一步就可以做“个性推荐”啦。

这份实习让我学到了不少东西,从一开始没有接触过NLP和Python,现在已经能写出爬虫程序,并且分析文本了。不得不提,我觉得其中最难的是中文编码和中文分词(哭),大多数语言(例如英语,法语,德语)等都是有空格来分词的,但是中日韩文这些亚洲语言,用起来就想这篇文章一样,只有句子之间有间隔,词与词之间是没有间隔的,要多做一份工作。至于中文编码嘛……谁写谁知道,说多都是泪。但是其实最后的成果比我预期的要差,主要是因为我们手里得数据质量太差了,信息有限,只能依靠爬虫去网络上抓取更多信息,但是本来就差的数据,抓回来的也不太高。

对了,上班第一天开的一个会让我现在都记忆犹新,不得不提一下。是一个百分点介绍他们的业务的会议。这是一个专业做大数据的公司,靠在他们的客户网站上挂代码,获得用户行为,在应用到个性推荐上。比如说,你在网站A上浏览了冰箱,那么你下次上B网站,他们就在首页给你推荐冰箱。不仅限于购物网站,新闻网站,门户网站等一切需要流量的网站都有用武之地。这个会议让我对大数据的应用叹为观止,以前就是听说过这么个概念,现在才真正接触到(讽刺的是,人类的一切最新的科技都会首先用在军事和消费上,呵呵)。说起来,我跟朋友们谈这个,他们普遍的反映都是很反感“个性推荐”,觉得这侵犯他们的“隐私”了。我对这个感觉还好,我觉得一个人只要是上网就不存在隐私了,网络上基本所有的数据都是公开的。

公司在浦东浦电路,每天要坐3个半小时地铁来回啊!写代码不累,坐地铁可累死了,而且上下班的时候正是高峰,人特别挤!实习期间经历了公司被万达收购,从陆家嘴投资大厦搬到世纪金融广场,可是距离只变的更远了(哭),给我的经验就是:以后上班宁愿贵一点也一定要住在公司附近,不然太浪费时间了。

20150824_180125

说起来我还是蛮认真的嘿嘿,基本上每天来的都很早很早。

20150810_081854

新公司某办公室发现了这件旗子——别拦着我!为了部落!

20150814_102939

离开学还有十多天,我的假期真正的开始了!我要在这段时间里完成之前写了一半但是没写下去的小玩具,请大家期待吧!这篇文章不谈技术,但是最近我会在博客上写写实习的时候遇到的好玩的东西~