按 ‘ infotech ’ 分类归档

程序员入伙书——编程语言

下载Python一章里,我说过请大家忽略“编程语言”和“Python”这些词的意思,因为那时这些词并不重要。

现在大家已经看到了一些使用Python的实例,我想是时候让大家了解关于编程语言的一些知识了。如果你懒得听我长篇大论,可以直接跳到文章结尾看总结。如果觉得我的扯淡还有点意思,请继续往下读。

我们说过,计算机不会自主思考,它所有的动作都是人们事先告诉它的。告诉计算机”遇到什么情况时该干什么“,就是编写程序,简称编程。既然要给机器发指令,它就得明白这些指令。

计算机本身能明白的、以及能操作的东西,只是一系列高低电平的组合,就像我们人类的身体只有一系列的化学反应和生物电一样。一个刚生下来的人只会吃、哭、拉、睡,却不知道怎么喊妈。你让他喊他也不会喊,因为他听不懂。在计算机世界里,我们把这种基础的电平称为“机器语言”,机器语言是在制造计算机芯片时固化在那块半导体里面的。

使用机器语言能编程么?能!你拍打婴儿的脚底板,痛觉末梢产生一些生物电,传送到大脑,他就开始嚎哭。“拍脚”是指令,“嚎哭”就是动作。较真的同学会说我这个比喻不恰当,因为“拍打脚底板”是婴儿大脑里运行的那个小程序的输入,“哭声”是程序的输出,无论“拍脚”还是“哭声”都不是程序本身。我首先感谢这位同学,提出这个质疑,说明你认真地看了前头的章节。其次,我解释说:判断这些行为究竟是输入输出还是程序本身,得看你怎样定义这个系统的范围。假如我在计算机芯片的一些管脚设置成事先想好的高、低电平,之后,在芯片的另外一些管脚上观测到了一次乘法的计算结果(同样是高、低电平来表示),我们既可以把设置的那些电平称为程序,也可以把它们称为输入数据。

跑题了,拽回来。刚才说到,计算机只能听懂高低电平组合成的机器语言。为了显得专业些,我们把高电平称为1,把低电平称为0。计算机里只有两个数字:0和1。我们眼前的计算机有许多花里胡哨的行为,能显示种种色彩,发出种种声音,那都是它组合各种0和1的结果。举个例子,一个橙色的像点至少包含24个电平,顺序是111111111000000000000000。一个灰色的像点则可能是100111011001110110011101。字母“A”在计算机里是01000001,而“#”在计算机里是00100011。
猛击阅读全文

程序员入伙书——初涉算法

在以后的讲解里,会陆陆续续地涉及到许多算法。所以这里先给大家心里垫个底儿。如果你没有看明白这一节,不用很担心。

在“程序在干什么?”一节的最后,我举了一个例子,来说明程序具有计算、流程控制、输入输出三个功能块。这个例子是“求”一个数字的平方根,但它不是在“算”,而是在“猜”。

如果我给它的数是3,它就先猜:1.5!然后自己验算一把:1.5 x 1.5 = 2.25,太小。于是它就再猜:2.25!(就是位于1.5和3正中间那个数)验算一下:2.25 写2.25 = 5.0625,太大。再猜:1.875!——1.5太小,2.25太大,那一定在它们之间了。1.875是1.5和2.25的平均值。1.875 x 1.875 = 3.515625,又大了些,不过大家可以注意到,数字开始接近3了。于是它再取1.875和1.5的平均值……如此反反复复地接着猜下去,可以预知,猜测的结果必然会越来越逼近3的平方根。

我们都知道,第一、计算机无法精确表达实数。第二、即使从完美的数学上说,3的平方根是一个无理数,也不可能通过有限次的有理数四则运算实现。所以我就对程序说,你也不用太自责,只要误差小于亿分之一,你就可以从循环里退出来了。这样就不会出现这种情况:由于结果的平方总是不能精确等于3,程序过于内疚而陷入无限循环的困境。

现在咱们往那个程序里加两条调试语句:

print('Please input a number: ', end = '')
n = abs(float(input()))
high = max(1, n)
low = 0
while True:
    result = (high + low) / 2
    print('What about %.10g?' % result)
    print("%.10g x %.10g = %.10g" % (result, result, result * result))
    if abs(result * result - n) < n * 1E-8:
        break
    if result * result > n:
        high = result
    else:
        low = result
print('Square root of %g is %g' % (n, result))

再来跑一下,看看每次循环的中间结果。
猛击阅读全文

程序员入伙书——程序在干什么?

程序员是写程序的,程序是干什么的?

我的独门总结:形形色色的程序,大到组成整个操作系统或者办公软件,小到打印一个九九乘法表,它们都有三个共同的功能块:

  • 计算
  • 流程控制
  • 输入输出

计算,不但是数学运算,也包括对语言文字信息的分析,判断异同、比较大小,都属于“计算”的范畴。如果没有计算,如果所有的数据、信息都不需要处理,我们要计算机做什么?当打字机使么?

流程控制,包括条件判断、循环、跳转。通过使用流程控制,我们可以写很短的程序,让计算机重重复复地执行成千上万的步骤,并且花样繁多。计算机虽然不会思考,但它们做明确具体的事情时还是比人速度快、而且重复性好。你让计算机做两个数相除,做一亿次的结果都是一样的,且它也不喊累。可让人来做的话,首先就是慢,也可能做错,做十次会不耐烦,做五百次会精神崩溃。小时候被老师罚抄作业十遍的同学,请自行默默回忆童年时的阴影。

输入:键盘、鼠标指令,从网络上接收服务请求,或者从硬盘读个图片……把外部设备上的电信号吸纳进计算机的过程,都算是输入。输出:在屏幕上显示一张图片、一些文字,往U盘上拷东西,播放音乐或视频……把计算机心里想明白的事情说出来的过程,这些都是输出。如果程序没有输入,那么它每次的运算都是从已知的、固定的条件开始,结果会单调得让人厌烦。学编程的时候,看到一群老年大专生用BASIC语言打印熊猫,以为自己在编程,心里的怜悯油然而生。如果程序没有输出,计算机有电没电的区别就不太大了,当然,冬天屋里冷的时候,多开个电器,确实可以更暖和一些。

可以说,所有的程序做的事情不外乎这三个概念。你打开网络浏览器,IE也好,FireFox也罢,你输入一个网址,按回车键,它就向网络端口上输出一个请求,向那个网址要网页,要来的网页从网络端口输入进来,浏览器反复判断每个传进来的数据流,看它们是图片还是一般文字,如果是图片,还需要做些解码工作计算摆放它们的位置,显示在窗口上。在这个回合里,计算、流程控制、输入输出都是齐全的。除了这三样,确实也没有其它的操作了。

说了这么多,我来演示三个例子吧。

第一个例子,是算从1加到100的总和,传说高斯用很聪明的办法搞定了这道题,我们来看看很笨很死脑筋、却擅长做高速计算的计算机是怎么做的。打开Python的窗口(说啥呢?),输入(虽然可以拷贝粘贴,但我更希望你亲自敲一遍):

total = 0
for i in range(1, 101):
	total = total + i
	# 请在这里多敲一两次回车(Enter)键,以使Python显示>>>提示符
print(total)

打字时请注意,Python对每行的缩进要求很严格,因为它认为这是表达程序结构的一部分,所以一定要按照这个例子里来敲。敲完最后一行“print(total)”,如果你看到了5050,就知道自己做对了。
猛击阅读全文

程序员入伙书——两个世界

作为程序员,我们常往来于两个世界之间:计算机世界和现实世界。为了快速地让你感受到这两个世界的不同,我举一个例子。请在Python(啥?)的“>>> ”提示符后输入这样一行:

int(0.7 / 0.1)

现在先不要按Enter(回车)键,停下来,听我解释一下:这句话意思是,计算0.7除以0.1所得的商,取其整数部分。这个简单的除法,你觉得结果会是什么?

7,对吧?现在,敲回车,看看计算机认为结果是什么。

>>> int(0.7 / 0.1)
6
>>>

😮 😮 😮

为了弄清楚这个6是怎么出来的,我们先把“取整数部分”去掉,只留下0.7 / 0.1——如果你曾经听说过“调试”这个词,我们现在就是在调试:

>>> 0.7 / 0.1
6.999999999999999
>>>

现在我们至少可以理解,为什么“取整数部分”之后的结果等于6了,因为6.999999999999999的整数部分确实等于6(虽然四舍五入等于7,但“取整数部分”的操作是比较憨傻的)。可是可是,为什么0.7 / 0.1不正好等于7呢?这就是计算机世界和现实世界的差别之一。完美的数学世界里,任意两个实数之间必然存在无穷个实数,而计算机不这么认为。因为计算机的位数有限,它能表达的实数是有限的,实数之间总是存在一个个“空隙”,在计算机的世界里,“两个相邻的实数”是合理的说法。不精确但是意思到了的类比是,在只能显示五个数字的计算器液晶屏上,刚刚比1.0000大的下一个数就是1.0001,而介于其间的其他数,如1.00005、1.0000342376,则无法被这个液晶屏精确表达。

说出来你可能不信,0.1就是一个计算机无法精确表达的数字。这个数字对于我们这些习惯了十进制的人来说,是如此的简洁。可是机器用二进制思考,在二进制的世界里,十进制的0.1是一个无限循环小数:0.000101000101…,无法被精确表示。

再考虑这段例子:

>>> 1e10
10000000000.0
>>> 1e10000
inf
>>> 

1e10的意思是1乘以10的10次方,计算机心领神会地把这个数字表达出来了。1e10000的意思是1乘以10的10000次方,计算机口吐白沫地说:这个数……太大了……这就是传说中的“无穷大”吧?
猛击阅读全文

程序员入伙书——下载Python并念诵程序员真言

想通过纯读书来学习任何技术,可能都行不通。我发现,即使你不编写程序,而只是把别人写好的程序亲自在键盘上敲一遍,都会有很强的感觉。默读一首诗,试图背诵它,不如念出声给自己听来得快。所以我恳请读者通过练习来掌握编程,练习需要用至少一种编程语言,我在这里推荐Python,后头的示例里,也会一直用Python来做例子。

你可以尽情忽略本篇里的“编程语言”、“Python”这些还不应该被提及的术语,它们目前一点也不重要。

对于早就是程序员的围观群众来说,我选择Python作为示范语言的理由有:

  • Python无需(看得见的)编译即可直接运行。
  • Python完全免费,拿来教学不涉及法律问题。
  • 使用Python的话,即使是初学者的程序,看起来也和牛人们写的一样悦目。(请呵呵大笑)

在Windows的机器上,下载并安装Python的步骤(其他机型需要去http://www.python.org自行发现):

  1. 点击 http://python.org/ftp/python/3.3.0/python-3.3.0.msi下载一个叫做python-3.3.0.msi的文件。把它存放在你的桌面上,或者一个你回头找得着的文件夹下。
  2. 下载完毕后,运行这个文件,接受一切默认选项,一路点Next就可以了。
  3. 安装完毕后,当你点“开始”或者“Start”按钮,再移动鼠标到“所有程序”或“All Programs”时,你会发现一个叫做“Python 3.3”的新建程序组,再移动鼠标到这里展开它,选择“IDLE (Python GUI)”,你会看到这个窗口:

当读者老爷们看到这个窗口后,我不想对大家说:“恭喜你!工具已经准备好了,现在请关掉窗口并期待明天的正式讲课。”正相反,我想请大家做一件十分重要、十分重要的事情。这个事情,就是念诵程序员真言,写下你人生中的第一个程序。让闪烁的光标伴随着你因激动而发抖的双手,在窗口提示的“>>> ”后面输入以下文字:

print('hello, world')

现在,停一下,请检查:

  • hello和world必须全都是小写字母。
  • world后面不要跟句点。
  • 逗号后面一定要跟个空格。

都确认之后,敲Enter键,你会看到窗口里有这些内容:

>>> print('hello, world')
hello, world
>>>

其中第一行print啥啥的是你敲进去的,第二行“hello, world”是程序的输出,而“>>> ”是Python期待你继续指挥它的提示符。

关于“hello, world”,传说,每个程序员必须尽早让自己的一个程序朗诵这句话,并且,除了朗诵这句话之外,这个程序什么别的事也不要做。念诵这句话必须做到每个字母、每个标点、每个空格都是精准正确的,否则,不但不能成为一个好的程序员,未来的编程工作中还会出现种种意想不到的失误(简称bug)。

现在,我可以说:恭喜你!欢迎入伙!你编写了至少一个程序,现在已经是程序员了!

程序员入伙书——序

公司里有个小女孩,在我组里工作一年半了。虽然在我组里,其实是挂靠一下。她的工作是数据录入,多是手工工作,体力上很辛苦,工资也委实不高。但她很敬业很努力,也时常做超越自己的事情。

我这个组里的其他人都是程序员,她坐在里头,耳濡目染地有了一些思路。每每有事,她还是很想用自动化的方法解决的。有这么一个机会,一个同事用Excel写了个数据发送程序,里面放了些用于统计及查错的公式,这还没涉及编程呢,已经引起她浓厚的兴趣。后来她还真的自己捣鼓出来一个检查数据是否已经完备的VBA,别管她请了多少人帮忙吧,总算是她自己推进的,更重要的是她做成了。我注解一下,在大公司里,做一件不同于常规业务职责的事,是很不容易的。

曾经有封信,从好吃懒做的印度同事发来的,信里问的是个技术问题,当时北京已经下了班,他们就把信发给了巴黎技术组的当班经理,不料这小姑娘当时在北京的办公室还没下班,就手把这个“技术问题”解决了。印度大窘,后来常常受到我们的挤兑:你们就不能多学点?你瞧瞧我们的小姑娘,也不是科班出身,才毕业一年多点,都不用技术员们帮忙就搞定了!

我觉得呢,很多事情,例如写程序,有些人说学不会,那是有两个原因:一、没兴趣;二、没法让他感兴趣。如果第一个原因是第二个原因引起的,或许还可以从表达手段上努力一下,拉他们入伙。像我刚才说到的这位小姑娘呢,她是感兴趣却还没有完全找到感觉,平时说话也总让人觉得糊里糊涂的。但我觉得,这个“糊里糊涂”只是非码农的经典思路而已,只要能上道,就可以改变。以我的表达水平,把她雕琢成程序员还是有希望的。人到我这里时一张白纸,如果被我画上画,而且还画得不错,拿出去能升值,是我最大的成就。

所以我准备写个编程教材系列,把只会使用“电脑”(对不起,我只称“计算机”)打字上网玩游戏的非科班人士变成程序员。不要指望读了这个系列能成为计算机科学家,因为我还不是。我也不想把这个教材称为傻瓜书,因为大家不傻。我本着平等的原则,称之为“程序员入伙书”吧。

面试拒人连载

先说一下仪表的重要。刚刚从校园出来的学生,穿得休闲不要紧,穿得搭配不好不要紧,甚至穿得破也不要紧,但一定不能臭……

今天这个同学,技术考试的分数不算高,本来给了我一些希望(前阵子总是遇见分数奇高、却没法要的)。但他暴露出的问题,让我还是叹口气,把他拒掉了。

先说个无关紧要的小事情,他的英文比较生,自我介绍里,说到“C++”时,发音是C加加。另外,这篇英文自我介绍明显是背过的,说着说着,头顶密密麻麻全是亮晶晶的汗。背到一半还是忘词了,在I和My之间来回跳盘。我决定替他解围,问了他两个没有背过的问题:How did you find this job? Why do you think you can work for us? 两个问题里,最长的词不超过五个字母。他没背过答案,卡壳了。

以下是灾难性的对白。

我问:如果你老板轻易地向用户许了两个项目,说都能两个星期内交货,而到你这里一瞧,每个项目都需要至少三个星期,怎么办?他说:跟老板商量商量,让他往后挪挪吧。我继续问:如果老板说挪不了呢?他说,那就是基本冲突,没法做了。

我总结说:就是说,老板说的是黑,你说的是白,完全对立的根本冲突,不能实现的结果,对不对?他说:对。

好吧,我心想,必须得确认一下,于是我决定问下面这个问题。

我问:如果你入职了,人事的同事把你带到一张桌子前,给你个电话,给你个本本,说,干活吧。底下的一星期,你准备怎么度过呢?
他说:那我就上网查查工作有关的资料,学习一下。
我问:你怎么知道工作有关的资料是什么呢?他说:那得看要做什么活了。
我问:你怎么知道要做什么活呢?他想了想答:人事的同事会告诉我的吧。
我说:他们管行政,不管你做什么的。他答:如果没人告诉我做什么,我就上网看书吧。
我问:上网看书的事情,不是在家也能做的么?他答:毕竟上班了么,公司里上网和家里上网的性质还是不同的。(微妙的意思似乎是:在公司里,就算是上网看书,也毕竟是领工钱的,不能辜负了公司的网络。)
我还在回味这句敬业的话,他自己发现有问题了,补充说:我可以看看周围的同学们都在做什么啊,看谁做的事情比较有意思,我可以打打下手,帮帮忙。

我阴险地说:我总结一下,你是说,第一个星期,你准备上网读读书,看看周围的同学们的工作,然后找你感兴趣的事情帮帮忙,是这样么?他说对对对。

我说:好的,星期五这天来了个人,走到你面前,跟你握手,说,你好,我是你的经理,过去四天一直在找你,你这四天怎么过的?你说,你在帮邻居们干活。经理说,这些人是别的工作组,跟咱们的工作完全无关。你怎么办?
他答:那就是人事把我带错桌子了。
我说:人事没有带错桌子,这个楼里的座位相当紧张,虽然后勤部门已经十分努力了,还是不能保证每个组不多不少正好能坐在一起。
他说:那就是后勤部门分得不好,弄得经理找不到我了。

既然都是大家对不起他,我还是把他拒了吧。

面试拒人连载

老实说,拒掉今天这位让我十分犹豫。他家境不好,没钱到北京来读研,而不是因为学习成绩的原因。小孩儿的技术反应很敏捷,能熟练修补代码中常识性质的错误。但他有一些让我很不放心的地方,我和人事唏嘘再三,很不忍地打了个叉。如果他的家境好些,我们的内疚感就会小很多。

我们感觉,他对工作机会太在意了,以至于隐瞒了很多真实的想法。

一、注意到他总是说人际关系最重要,我就问他,如果同事总求他帮忙,还都是帮两天工作量以上的大忙,临了对老板说是自己完成的,他如何应对。他回答:大家是同事、朋友,多请我吃顿饭就是了。我说,我们的同事天南海北,身在印度的同事,没法子请你吃饭啊。他犹豫很久,答:我觉得这样的同事不会有的。我觉得他的脾气好得失去了底线,即使他真的是个圣人,这样的忍让也决不能被称为团队合作。

二、我问他做过的项目,他说做过一个采集数据的系统。我问是什么数据,他说是一些信号。我问是什么信号,他说是电信号。我问是什么电信号,他说是电流电压信号。我问是直流还是交流,他说“也有一些直流”。我问是什么东西在用电,是厂房呢、城市呢还是什么别的,他说是个显示屏。我问是楼外面挂的那种广告屏么,他说不是,就是个小屏。我觉得从他这里挖信息太难了,纯管理型的经理,更会被累死的。

三、他说话时眼睛不太看人,两只手架起来,遮挡着嘴唇部位。我认为这是“有些事我不想告诉你”的肢体语言。

四、当我问他,你觉得自己有什么地方亟待提高的?他说自己和考上北京的老同学们还差一大截。我说,我们了解那不是你的错,再说你不需要和别人比,跟自己比就行了,你觉得哪里不够好?他说,我的适应能力挺好的。我说,我是问你觉得哪里还不够好。他想了想,说,我觉得我整体来说都挺好的。我不是要强加给他我的想法,但他的英文口语不忍卒听,十分明显,如果是我,立刻就会用“提高英语水平”来搪塞过去。

面试拒人连载

今天拒了一个。我进屋时,他已和人事部的同事聊了两分钟,脸上带着微微自负的笑容,撇着嘴的那种笑。谈话中了解了这个笑容的来源,他上学的这几年比较顺利,上本科时发现老师给他挑的专业不是他喜欢的,于是成功地完成了学业转型,硕士和本科的专业完全不同。

人是个聪明人,技术也确实过硬,机考分数排在前3%。但他在面试中,有不合我意的失误如下。

一、语速过快(不喘气匀速蹦字15秒以上),喜欢抢话头,每每从我所问问题的90%处打断,难以认可他是个好的倾听者。说话时眼睛不看人——也许和中国的传统有关,不算致命缺陷。
二、请他叙述一个难忘的经历(实想了解一个他做过的成功项目),他首先想起了专业转型前的不愉快经历,然后才想起了最近实习时做的事。对于最近实习时的经历,最让他难忘的,是部门经理每天带着他们玩三国杀,所以很愉快很难忘。我得说,这说明他很诚实,不按照我想听的来回答,但这些属于对求职没有帮助的信息。
三、期望值过高,想着在大公司做叱咤风云的事,不愿意做“杂七杂八的小事”。注:越是大公司,每个人越像个零件,越不可能有叱咤风云的事做,反而是十几个人的小公司,才会出现每个人都是顶梁柱的现象。
四、假设他和同事出现分歧时,他的回应是“完全不争,采用同事的方案”。注:固执己见和立刻投降,在我眼里,都是不愿意沟通的信号。
五、假设老板给他一个不可能按时完成的活,他能想出来的唯一对策就是“加班”(7×24,连续工作两个星期)。另外,他试图推翻此问题的基本假设,觉得老板经验丰富,既然老板说某天前能完成,那就一定有按时完成的可能性。
六、当他不同意我的想法时,不说“我的想法不同”,而说“你错了”。
七、他想取得北京户口(很正常),希望我们考虑他的“特殊情况”。我问他为什么觉得自己有特殊情况,他认为自己的本科和研究生专业迥异,所以特殊。人事的同事后来和我对照观点时说,她心里“哦!”了一声,也印证了她同样观察到的自负笑容的来源。
八、面试快结束时,他暴露了最后一个问题。他问多久能够给回复,我们说最多两个星期内,因为我们是一批一批面试,一批一批取的。他说这样会耽误他的判断取舍,希望我们“考虑他的特殊情况”(又来了!),改变招聘流程。注:在风险存在下,他作为求职的一方,应该更改自己的博弈方案,而非让招聘方更改工作办法。

总结:技术没问题,学习能力强,但自负、极自私,希望大家围着他服务,不愿和人交流沟通。拒。

专业服务器比笔记本还慢?

新到刀片服务器一台,郑重地装到了机房里,总算在公司有点产业了。

周六就放大长假,所以周四忙到半夜,周五早晨接着来,先把组里的文档管理系统从一个破破的笔记本转移到刀片上去。转移完毕,一刷浏览器,每个页面都要延迟两秒才能打开,而过去在笔记本上,文档系统的反应都是迅如疾风啊!专业大刀片和专业机房,怎么比放在邋里邋遢的办公桌上的笔记本还慢啊!!! 😕

文档管理系统是MediaWiki家的,在Apache平台上,使用PHP存取MySQL数据库。

是Apache慢么?由这个Apache管理的其它独立网页都是打开得飞快。
是PHP慢么?把那个独立网页从HTML改成PHP程序输出,还是刷屏快到连闪烁都看不出。
是MySQL慢么?从一个MySQL客户端单独访问,依然是迅雷不及掩耳盗铃。
合在一起之后的MediaWiki,却又是龟速了。

用这台机器的浏览器访问自己,也是同样的现象,这说明网络和防火墙设置不是原因。再说,如果真是网络问题,那么独立网页和MediaWiki就只是“慢”和“更慢”的区别。

后来不知怎的,就留意到MediaWiki本地配置文件LocalSettings.php里的

$wgDBServer = "localhost";

心想,如果把localhost改成绝对的IP地址——127.0.0.1——呢?这么改了一下,MediaWiki就立马变身神行太保了。

难道系统认出localhost就是127.0.0.1,还需要等两秒种?检查一下\windows\system32\drivers\etc\hosts,居然

# 127.0.0.1  localhost

真的被注释掉了!注释的前头还加了一行注释:“兹事体大,着DNS同学办理。”难怪,时间都被DNS耗费掉了! 😯

速度问题解决之后,忽然又想起一个推论:如果MySQL和Apache分装在这台刀片的两个VM上,那么,MySQL服务器的IP地址就会生写在Apache那边(俺们的系统还没复杂到要用DNS来处理),然后,当Apache来访问MySQL时,就会出现“两台机器互动”比“一台机器自己动”还快的诡异现象。 😉