唠唠python(2) -- 初识ABC

一周又过去了,时间过的真快。冰心奶奶说昙花只在夜里开,而且花期极短,开放时能听到“簌簌”的声音。时间有没有声音呢?

重新认识计算机语言

python的作者叫“吉多”(听起来像名贵犬种)。

我们之前说“吉多创造了python语言,并教会了计算机使用这门语言”,其实这样说法不太准确。

事实上,计算机只认得一种叫做不可描述的语言,而且我们人类是无法搞懂的。所谓的教会计算机使用一门语言,其实是我们请了一个翻译,将我们能认识的语言翻译成计算机能懂的不可描述语言。

请个翻译

“请翻译”,就是我们在计算机中装一个翻译软件,跟有道词典这种翻译工具类似。区别是,有道词典翻译给我们自己,python翻译器翻译给计算机。

请个python翻译很简单,如果你是windows(瘟到死)系统,戳此链接,就可以从官方下载到一个安装包,双击就可以安装了。

如果不是windows系统,恭喜你,你的系统已经默认安装python了。

跟计算机打个招呼

记得自己在幼儿园时,看到其他小朋友玩得不亦乐乎,非常想跟他们一起玩耍,却因生性羞怯,扭捏着不好意思向前。很多时候,我拒怕新东西,拒绝探索这个世界。但真当我们迈出了第一步,世界在我们心中的印象就更加清晰了。

打招呼,虽然是交往的一小步,却是我们人生的一大步。

计算机刚诞生的时候,它是个庞然大物。跟这个怪物打招呼,可不是件容易的事。

但世界在发展,现今已有各种各样的计算机语言,沟通变得前所未有的简单。

就我们使用的python语言来说,与计算机沟通只需要简单两步就可以了。

  1. 安装一个翻译器。如果你是windows系统,下载链接已在上面给出,如果你已经下载并安装,恭喜你第一步已经完成了;非windows用户可以直接跳过这一步。

  2. 唤醒这个翻译器。这一步也非常简单。对于windows系统,点击开始 -> 运行,输入cmd并键入回车,这时系统会打开一个神秘的黑色窗口;如果是其它系统的用户,找到一个叫做终端的软件打开,也是一个黑色窗口。然后,在黑色窗口里,输入python并键入回车,如果出现下面的文字,表明已经成功唤醒我们的python翻译器了。

1
2
3
4
Python 2.7.13 (default, Dec 17 2016, 23:03:43)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

这一坨东西我们不用理会,只要确保不是Bad command or file name或者是带有error字眼的语句,就表明我们已启动成功了。

失败了怎么办?可以搜索一下或者给我发邮件,我会对你负责的!

现在输入一个"hello"看会发生什么。

1
2
3
>>> "hello"
'hello'
>>>

我们输入了一个"hello",它又回给了我们一个'hello'

这样无聊的结果也真是令人感动,完全没有一波三折的快感,跟琐碎的生活一样枯燥。

无聊的背后有什么有意思的东西

太他妈没劲了。

非也。

我们刚才跟计算机打了个招呼,神奇的是,他听懂了,并回应了我们。而无聊的是,我们给他什么,他就回给我们什么。

我们看到了>>>这个符号,它的意思是,“跟我说点什么吧,我在听着呢”。多忠诚!

我们输入的hello两边有一对"号,这表明我们在说一句话,而不是要计算机帮我们做个算数题。

那现在我们可以让他帮我们做算数题吗?当然可以!

学习简单算术

刚才我们给计算机一句话,他又把这句话回复给了我们。有点无聊。

下面我们来做点更有意义的事,让计算机帮我们做个算数题。

我女朋友帮我举了个例子:我们需要一种元器件956包,每包10000个,每个0.0016元,那么总共需要多少钱呢?

好便宜啊!嗯,我觉得是个好例子,python已经开始辅助我们工作了。

在我的印象里,10以内的加减乘除运算是最开始接触的算术题,部分甚至可以借用手脚辅助完成。说到乘除法,小九九还算简单,更像是语言,靠记忆。但是100以内的乘除法,对我来说已经有相当的难度了。

我记忆还算不错,对于加减乘除,当初还有一句口决,叫做先乘除后加减,如果先加减怎么办呢,用括弧()

我们可算是非常幸运的,在甚至还不明白为什么要学这种鸟玩意的很多年前,就已经掌握了算数的基本原则。python里面的简单算术,甚至都不需要我们再学一遍了。

现在,我们只需要告诉python翻译器元器件总价格的计算公式,python就可以翻译给计算机做运算了。我们来试一下:

1
2
3
>>> 956 * 10000 * 0.0016
15296.0
>>>

哇噻,我们的计算机计算非常迅速,一下子就帮我们算出了答案。果真是人如其名,这是一只战斗鸡。

记得以前,我参加珠心算那会儿,试题里有很大一部分,是多个多位数字求和,做得多了很容易出现一种自我怀疑:好像有一位记错了?不过对计算机来说,只要我们输入的正确,可以完全相信它的计算结果。我们负责精确地表达,它负责精确地执行。

上面虽然只有乘法,但+ - x ÷聪明的我们已无师自通了(其实多年前,我们就已经掌握了)。需要注意的是,计算机语言多用*来代表x,而用/来代表÷

举个例子,(0.31 + 0.43) * ((0.26 + 0.45 - 0.31) / 0.47),看明白了这个公式计算的是什么,我就不用再叨叨了。

唠唠python(1) -- 开学典礼

为谁而写

有一天,我女朋友跟我说,你帮我处理一个电子表格吧。

最开始,我做了一个vba(一种计算机语言)脚本,觉得不行。因为使用起来太过繁琐,这可能会让她崩溃,也可能会让我在回答各种问题的过程中崩溃。

之后又写了一个python(另一门我们将要详细讨论的计算机语言)脚本,还是不行。要使用这个脚本,需要学会安装python这个软件,然后安装一大堆额外的东西。这也太他妈不方便了。我是不会把这么一个鸟东西给出去的。

后来我想到了最佳的解决方案:让她学习一点计算机语言。“一点”以足以应对这种简单繁琐的操作。但是我找到的资料都不是很理想,很少有面向非计算机专业的。

这些文章就是为这类人群准备的,我们(请允许我角色带入)没有系统地学习过计算机方面的知识,而又在日常生活工作中经常用到计算机,我们试图通过与计算机更有效地沟通,来提高自己的工作效率。但是报个班又太不值,毕竟班里大部分同学当初是奔着程序员梦进去的。

简而言之,这一系列文章是为非计算机专业而又意识到计算机的重要性,想要快速与计算机建立高效沟通以提高工作效率的人准备的。

与其它同类文章有什么不一样

在网上已有非常非常多的《python从入门到出家》类的文章或教程。

他们有的打着“简单”、“易学”的愰子,随便翻一下,里面充斥着“条件语句”、“函数”、“异常”等看上去屌炸天的词汇,全然不顾我们的感受。

他们并没有站到我们的角度来思考问题。现阶段,我们并不想知道“异常”是个什么东西,而只想尽快让计算机帮我们计算出这批元器件缺少的数量,然后去补货。

这些词汇和程序员式的思考方式,严重阻碍了我们的学习过程,损耗我们的注意力。很可能有那么一天,在我们尝到与计算机高效交互的甜头前,终于忍受不了各种纠缠在一起的专业名词,而选择了结束这个恼人的过程。然后留下一种感觉,“程序员都他妈是神经病”。

当然,这篇文章只是提供另一种学习python的体验,而上面所说的这种情况也只是一种假设。如果你愿意听一个人每天唠叨几句(有可能只是十分、二十分钟),自己同时又能有所收获,以至最后竟然能流畅地与计算机沟通,那你就可以继续往下看了。

这里没有乱七八糟的词汇,我希望自己能以一个中年大妈唠家常的姿态给大家讲述一下与隔避老王沟通的技巧。所以你也不用有什么负担。

我是中年大妈,不要有压力

为什么是python语言

计算机语言,说白了,就是我们与计算机沟通的工具。比如,我们跟邻居沟通用汉语,而跟美国人沟通用英语。我们与计算机沟通,用的是计算机和我们都可以听得懂的语言。

计算机就像一个语言天才,它精通多种语言。不幸的是,没有一种是我们人类的语言。也就是说,要想与计算机流畅地沟通,除了学习它使用的语言,我们别无他法。

计算机语言有很多种,比如A语言、B语言、C语言等。甚至我们可以创造一门我们自己的语言来教会计算机,然后用这门语言与它沟通。正如我们的祖先创造了汉语,并让它普及于世一样。

既然计算机能使用这么多语言,我们想要与它沟通,自然最好是选择一门学习起来相对容易的语言。python语言就具有这样的特质,它真正的简单易学,而且学习曲线可以非常平缓。也就是说,我们完全可以一边享受它给我们带来的切实好处,一边进一步的学习以更好地与计算机沟通。

我能得到什么

想像一下,如果你学会了一门外语,就可以流畅地与老外沟通交流,还可以更方便地在国外打到车。节省了你的时间和精力,你可以多喝几杯茶了。

这些文章里没有语法结构、俚语俗语,当然并不是说它们不重要,你可能以后会感兴趣。这里更多的是教你在异国他乡(计算机的世界),更好的打到车,更快地找到饭店,或者是雇佣一个保姆帮你打扫卫生。

你可以用你的想象力去工作,把自己从繁琐的工作中解放出来吧。 – 这是我承诺给你的,学不会不收费。

简单了解python语言

终于讲到我们的python语言了,这篇文章只是开个头,我们只要有一点印象就可以了。

就像前面提到的:“我们可以创造一门我们自己的语言来教会计算机,然后用这门语言与它沟通。”python语言就是这样诞生的,作者创造了它,并教会了计算机使用这门语言。

关于python的介绍其实就这么多,下一篇文章我们就可以用这门语言跟计算机进行简单的沟通了。是的,计算机语言就是这么容易使用。

“安静”的三mămă

我的三mămă

有一次回老家过年,听到门外狗叫。我探出头去,第一次看到三mămă。面无表情,行走缓慢。

那时刚好年尾,仿佛有做不完的活。炸年货,打扫卫生,blahblah一大堆。

她还没走到屋来,我娘说,她是你三mămă。平时不怎么说话,顶多挤出一个“嗯”字。我们要炸东西,你跟她聊一会。

进屋后,她一言不发。我当时找了一句话(忘记说的啥了),她果然回答了我,用了一个小心翼翼的“嗯”字。

我猜想可能是三mămă大脑的某一处没有发育完善。

我的内心是崩溃的,当时想跟她说一句,“你有毛病啊”。但是碍于她辈份在那,我自然不能将我的这股子劲表现给她。

我的同事

有一次,我看到一个同事。我就跟个傻逼似的直勾勾盯着他看,一言不发。可能是看得他发毛了,就对我点了个头,“嗯”。

而就在那一刻,我产生了一种似曾相识的感觉。

我突然醒悟,其实我恰好也是这样的一个“有毛病”的人。为了展现友好(而并非发自内心),就冲着同事傻呵呵的笑,却更显局促。

而这次我有了一个明显的优势,我不再像上次那样隔了辈份,而终于可以理直气壮的指着自己的鼻子说:“你有毛病啊!”

她就是放大了的我

是的,三mămă让我看到了自己的某一面,而她恰是我那一面的极致。

有时候我们混在人群里,可能都忘记了自己是怎么一回事。而恰好有些纯粹的人(也可能是先天原因),让我们重新认识到了那部分不易觉察的自己。

遇见三mămă让我感觉很幸运,却为我们的个性日渐模糊而感到悲凉。

一方面,我看到了做到极致的好处,不管极致的好或是极致的坏,当被用来做参考时,都是不用费太多脑力的。

另一方面,我们身体或者心灵的某处,可能会因各种原因而被深埋。感受它,接受它的好与坏,就变得很重要。

我决定,要认真的与自己相处。你有多好,你有多坏,你都是我的一部分,我始终爱你。所以,不要因害怕而隐藏自己。

撞残的飞机

昨晚做了一个梦,买了一架小型私人飞机,然后在屋外试飞,云里雾里,怡然自得。结果在降落的时候撞到了院里的墙壁,把飞机屁股撞烂了一块。而后又试飞了一次,结果在降落的时候又撞到了墙壁,这次屁股都给撞冒了烟,感觉到当时心里难受极了。

为什么要把这些没头脑的破梦记录下来

梦到底是什么呢?它其实是我们潜意识的表现。说到潜意识就有趣了,在晴天白日,它就像是潜入水下的怪物,我们很难察觉。而梦很妙,在梦里,这些怪物们会浮出水面,变换一种形式出现在我们面前。

对,变换一种形式,所以它要告诉我们的,并非显而易见的。所以,就有了周公解梦。

记得小时候,过年我们买了一个日历,一日一页,每页一个周公解梦。那时,我每做一个梦,都要去翻找对应的那一页,看看这个梦到底是什么意思。结果最后把日历翻得破烂不堪。这是我对梦的一个很早的记忆。

如何通过梦找到另一个更真实的自己

梦的意义,就是帮我们找到那个潜藏的、不易觉察的自己。它更真实,因为它是我们身体放松状态下的感受,受到的压力更小,所以更容易舒展自己。

它在帮我们找到更真实的自己。这听起来太棒了,我们自己就会引导自己找到更真实的自己。

但是实现起来却没那么容易,它需要练习,如何练习呢?

首先,我觉得《周公解梦》有时是靠谱的,但有时是不靠谱。“有时不靠谱”就意味着它不靠谱。虽然听起来有点让人沮丧,但还好,我们可以参考一下,毕竟还有我们自己把关一下。

然后,我认为心理学对解梦很重要,同时它又是我们了解自己的另一种途径。这觉得这就是科学的好处,让不够清晰明确的概念慢慢形成体系框架,使得后来人可以通过在前人的基础上进一步完善,科学得以继续往前发展。人类终于通过自己的方法,即科学,实现了跨越时间的,前辈与后辈的合作。

这个梦到底意味着什么呢

回到我这个梦,对我来说到底意味着什么呢?

我利用网络,查看了梦的解释,五花八门,什么大难临头,什么胜利凯旋,什么人际关系转好。这叫人怎么信,又怎么能安抚我那不平静的心。

我在梦里有一种事物被破坏的感觉,自己心爱的东西被自己毁坏了,有一种说不出的难受。

飞机对我来说,是一个“挑战”的意象。

于是,我回想起了这个阶段做的事情,最近在做一个编辑器插件,用来辅助之前开发的一个系统。开发用的语言是自己之前没怎么用过的,语法结构、常用库啥的都得学习。这么想来,我是很担心这个项目会失败的。但因平日忙工作,可能这个担心自己并没有很清楚的意识到,而在梦里,另一个自己告诉我,我其实挺担心这个项目会被我搞砸的,尤其是别人没做过的东西。其实是担心搞一个新的方向的失败,它个梦就是现实的心理状态的一个投射。

所以这个挑战的意象,我觉得更像是挑战自己的内心,而非现实的处境。

写到这里的时候,我感到了幸运。毕竟是在做自己之前未尝试过的东西。失败其实并不可怕,我们又做了一个方面的尝试。

Git之对象数据库

数据库,顾名思义,即存储数据的仓库。

我们的Git是一个关系型对象数据库,怎么理解呢,它主要管理对象及对象之间的关系。而对象间的关系,组成了一个图结构。

图结构

我们先来看一下Git里对象的关系是怎样的。如下图。

git-objects.png

这是我用git-show-objects工具生成的某个Git仓库的对象关系。

矩形框(包括折角矩形框)即我们要研究的对象,而椭圆形是我们的指针。下面我们来分别看一下Git里的对象和指针。

对象

Git中的对象主要分两大类:不可变对象可变对象

不可变意味着,如果对象的某个域要发生变化,我们会创建一个新的对象,而不是修改原来的对象。

这就有几个很有意思的事情:

  1. 频繁创建对象会占用大量磁盘,但它会带来更好的灵活性和可跟踪性
  2. 不可变的对象更安全,可以共享使用,这在一定程度上又节省了磁盘

对于可变对象,由于其域可变,故我们是决不可能用它来保存历史的,但是保存临时的或一次性的数据则非常理想。

不可变对象

Git的图结构主要是由不可变对象组成的,Blob、Tree和Commit是我们接触最多的三类不可变对象。

Blob

Blob对象用来保存我们项目文件的内容,对应上图中的折角矩形。

有一点比较关键,Blob对象只保存文件内容。这就意味着,如果我们有两个不同的文件,而其内容竟然一致,好了,我们只会生成一个Blob对象。

Tree

Tree对象用来保存我们项目目录的内容,对应上图中的蓝文字矩形。

跟Blob对象一样,如果我们有hello1/dir和hello2/dir两个目录,而两个目录的内容竟然递归相同,那我们的两个dir只需要一个Tree对象就可以了。

Tree对象内保存着一个列表,它的每一项,都是一个文件名+Blob对象目录名+另一个Tree对象(子目录)。

Commit

Commit对象用来保存我们的提交动作,对应上图中的橘红色矩形。

Commit对象里保存的信息比Blob和Tree都要多,因为它已经是我们经常访问到的对象了。

Commit对象里有我们想知道的作者提交时间 信息,它还保存着此次提交的父提交。当然,父提交有可能是两个,三个或百八十个,只要你喜欢。

可变对象

Git中的可变对象最典型的就是Index对象,它是一个全局对象,或称其为单例对象。

Index对象维护着当前Git对应的文件及状态,是我们操作Git的入口。它维护一个列表,每一项包含了文件的mode对应的Blob文件对应路径和一些Git自己使用的标记。

指针

上面提到保存着父提交保存着对应的Blob,那这些是以何种类型保存到对象的域的呢?

答案是哈希值

我们知道,在计算机中,一个对象是有一个内存地址对应的,而Git的对象,用的是对象的哈希值。即,Git计算某个对象的哈希值,使用此值作为文件的路径,并将对象的内容序列化后存储到该路径。

实际上,Git将其要维护的对象统一存放在项目根目录的.git/objects/位置,并以对象哈希值的前两个字符作目录名,剩余字符作文件名,生成对象目录。

我们之前说,Index对象是我们操作Git的入口。指针,即是我们访问对象的入口。

Git中的指针直接或间接指向Commit对象,分为常量指针和变量指针。它们对应上图中的椭圆形标记。

变量指针

随着我们对Git的操作,变量指针的指向有可能发生变化。

Head、Remote

变量指针就像我们的书签,标记着我们当前看到了哪一页。

最典型的变量指针是Head(Remote),也即是我们常说的分支。如上图中的heads/master,它对应我们本地的master分支。

HEAD是一个特殊的指针,跟Index相似,它有且只有一个,顺着它指的方向,我们总可以找到一个Commit。

这里要注意,HEAD正常情况下是指向Head的,但上图中它直接指向了某个Commit,这就是Git里面的游离态(detached)。

常量指针

常量指针是一旦创建,就很少发生变化的指针。注意,是很少,并非没有。

Tag

Tag是常量指针的典型,它主要充当我们的标记笔,考试画重点必备。

例如,我们可以用它来标记一个稳定的发行版本对应的Commit,以供伙伴们检出或下载。

常用操作

git init

初始化仓库,主要是初始化.git/目录,创建Index对象、HEAD指针,以准备接下来的工作。

init.png

git add

创建Blob对象,并将对应文件添加到Index对象。

add.png

git commit

递归创建Tree对象,创建Commit对象,并保存根目录对应的Tree对象。更新HEAD指向的指针的指向。

commit.png

问题

此时,一个简单的提交就完成了。当然,这连一个开始都够不上。

如果这三个命令你都理解了,不仿实操一下以下几个问题:

  1. fast-forware是如何操作的?
  2. 上面提到过detached,它有什么问题,应该如何避免?
  3. 根据Git的实现原理,如何设计系统可以更好的利用磁盘空间?

其实第三个问题恰是我们设计简洁系统的一个原则。

参考

根本停不下来?可以看一下maryrosecook写的《git from the inside out》,如果看英文费劲也可看一下我的粗陋翻译《彻底理解git》。

自己创建一个测试仓库,使用git-show-objects工具,边做边观察一下发生了什么。

为什么我不使用JetBrains的屌炸天编辑器

首先解释一下,JetBrains并没有出过一款叫做“屌炸天”的编辑器。

作为一个提到编辑器圣战内心就无比激动的码农,我使用过JetBrains的大部分产品,从开始的PhpStorm,到PyCharm、Intellij IDEA、CLION、android studio,这些产品我都有摸过。

JetBrains生产的编辑器无疑是非常贴心的,代码补全、智能提醒、强大的重构功能,等等一大坨超级特性曾经让我爱不释手。

说到曾经,为什么是曾经爱不释手呢?

有一段时间,我的主要工作集中在脚本开发上。这让我第一次意识到了这种大型IDE的笨重。

后来,我开发一个基于django的系统,最初使用的是vim + 自已找的一大批插件。系统开发完后,我想起了被遗忘在角落的PyCharm。这时,我打算重新拾起这个屌炸天的编辑器。

此时,我已经是vim的重度用户了。为了延续vim那妙不可言的触感,我在PyCharm里安装了IdeaVim。不过用了没多久,就感觉哪里不对劲起来。

好了,BB了这么多,以下才是文章内容。

为什么我不使用JetBrains的屌炸天编辑器?

真的很棒

JetBrains的编辑器真的很棒,界面非常漂亮,而且非常智能,就像你编码时有一个专家在你身边一样。

如果是初学者,你值得拥有。

启动慢

启动真的非常非常慢。

emacs对此有理:别看我启动慢,但我一天只启动一次,启动一次在里面宅一天。

但是你JetBrains不行啊,尤其是对于运维开发的同学,很多时候是跟脚本打交道,而且要跨机器,JetBrains做不到。

我不习惯把一个笨重的软件放那里放一天,除非8个小时中我要在里面呆6个小时。

编辑体验不够流畅

有的人可以做到,主动关闭自己的听觉,这时他们就真的听不到了。

如果你做不到,你要想想,敲个字符它就给你跳个小灯泡,还主动问你要不要来杯咖啡是个什么意思。

我以前一直觉得vim的界面可真够简陋的,给我显示个文件夹图标吧,或者让我在编辑器里起个bash玩?

搞飞机!编辑器是用来编辑的,NERDTree还帮我们实现了一些文件浏览的功能,还不知足!

我以前有一种想法,一定要让编辑器最节省按键。所以搞了一套非常神奇的一字码快捷键的代码片断来自动补全。

但是当我思考编辑器想要给我什么的时候,我还是被自己吓了一跳。

编辑器帮我把我头脑中的想法通过指尖表达出来,并纠正校对。从这个角度讲,如果为了省个按键,把if定义成了i,那么在之后的时间里,我们的思维势必会被这个i扭成一团。流畅地表达想法很重要,最好是一气哈成。

JetBrains的界面真的是太棒了,但是感觉自己游在里面,注意力都被目的之外的东西分散了。

然而还是得看习惯

如果你是一个已脱离智能提示这种高级趣味的码农,如果你已有足够的经验来判断是非,还是建议你多用用朴实无华的编辑器(绝不包括notepad)。

当然,还是一个习惯问题,我的老大就在用JetBrains的产品,我有很多优秀的同事也在用。

这不是选举,你也不必投票。

所以JetBrains产的编辑器真的非常棒

闲暇时,我还是会打开PyCharm,欣赏一下这惊艳的UI,然后关掉它,想想生活真是很美好!

16年逝,17年始

屎屎屎,都是屎。。。

一年又转一年,感觉白驹过隙的,是否又废了这365天,过成了一个老爷爷老太太的模样?

关键字:读书

16年的关键字该是读书,虽然量不大,但还是开了个好头。也多亏自己这浮躁的嫉妒心被《微信读书》抓个正着。

认知:钱到底是什么

16年,自己的认知发生了很大的变化,特别是对钱的认识上。

之前晚上转火车都不舍得花钱住店。

16年去过几次海底捞,终于明白海底捞对我意味着什么了。

钱是等价交换物,是一把衡量价值的尺子。

对个人来说,比钱更珍贵的东西,我现在找到了这么几样:时间、精力、好心情。

16年第一次在得到上,狠下心订阅了400块的专栏。其实,没过几个星期,我就知道,花出去的钱已经变换成更重要的知识回赠回来了。

这几样比钱更重要的东西,成了我在kindle花几百块买电子书的理由:随着互联网的开放,我们当然可以找到大部分资源,但是找资源的过程中,我们有可能会失去比金钱更重要的东西,时间,精力。

关于“老好人”

年底最大的收获是,下定了决心,不再做一个虚假的“老好人”。

转头一看,却也已经带着这个面具欢快的生活了二三十年。“老好人”并非一条不归路,但走地越久,越像是一个干瘪的僵师,倒更像是老人家说的,离坟墓越来越近。

不要为难自己,做更真实的自己。

Linux命令之iostat

iostat来自sysstat工具包,可以查看CPU和系统磁盘IO的统计信息。本文主要介绍iostat的主要命令参数和输出的部分解释。意在帮助不熟悉的用户入境,高级用户可以直接查看man page。

用法

iostat [ options ] [ <interval> [ <count> ] ]
  • opions 选项
  • interval 每隔多少秒统计一次
  • count 连续统计多少次

注意:如果没有提供intervalcount选项,则系统只统计一次。统计结果是上次统计(如果没有统计过,则是系统启动时间)到本次统计的数据。

输出

执行iostat的输出如下:

Linux 3.16.0-4-586 (oogway)     06/02/2016     _i686_    (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.19    0.00    0.39    0.18    0.00   97.24

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               1.74        24.40         3.32     222286      30252

第一行:系统信息

系统信息的输出和uname -a的输出类似。

  • Linux 内核名称
  • 3.16.0-4-586 内核发行版本
  • oogway 主机名
  • 06/02/2016 当天日期
  • _i686_ 机器硬件名
  • 1 CPU CPU个数

第二行:CPU利用率

CPU利用率的信息和top里的CPUT信息类似。

  • %user 没有修改nice的任务的用户态时间占比
  • %nice 修改过nice的任务的用户态时间占比
  • %system 系统态时间占比
  • %iowait 等待IO的时间占比
  • %steal 虚拟cpu等待supervisor的时间占比
  • %idle 空闲时间占比

第四行:设备的读写信息

  • tps 每秒读写请求次数
  • kB_read/s 读取速度
  • kB_wrtn/s 写入速度
  • kB_read 读取量
  • kB_wrtn 写入量

常用参数

统计次数及频率

如果我们希望每一秒统计一次数据,连续统计10次,可以iostat 1 10

查看扩展统计信息

可以使用-x参数查看扩展的统计信息。

iostat -x输出如下:

Linux 3.16.0-4-586 (oogway)     06/02/2016     _i686_    (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.65    0.00    0.39    0.18    0.00   96.79

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.56     0.37    1.21    0.30    20.00     3.66    31.28     0.01    3.79    2.85    7.63   1.74   0.26

统计信息多了的这几项分别是:

  • rrqm/s 每秒读请求合并数
  • wrqm/s 每秒写请求合并数
  • r/s 每秒完成的读请求数
  • w/s 每秒完成的写请求数
  • rkB/s 读取速率,同kB_read/s
  • wkB/s 写入速率,同kB_write/s
  • avgrq-sz 请求的平均扇区数
  • avgqu-sz 请求的平均队列长度
  • await IO请求的平均耗时
  • r_await 读请求的平均耗时(ms)
  • w_await 写请求的平均耗时(ms)
  • svctm IO请求的平均服务耗时(该指标在未来将被移除)
  • %util 单位时间内IO请求占比。当达到100%时,说明系统IO已饱和(RAID和SSD除外)。公式(r/s+w/s) * (svctm/1000)。如果做了RAID或使用了SSD,这个值就不可靠了。

Linux命令之top

top命令可以动态实时地显示系统的运行状态,它的输出包括系统信息、进程信息和线程信息等。这篇文章主要讲解top输出的各项信息,以帮助用户更好的理解和使用top。

top的输出信息

top命令在我本地的输出如下:

top - 10:06:56 up  2:38,  1 user,  load average: 0.00, 0.03, 0.05
Tasks:  74 total,   1 running,  73 sleeping,   0 stopped,   0 zombie
%Cpu(s):  5.0 us,  0.7 sy,  0.0 ni, 94.0 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:    772276 total,   281820 used,   490456 free,    30140 buffers
KiB Swap:   976892 total,        0 used,   976892 free.   126516 cached Mem

 PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
1359 root      20   0   69700  30232  13524 S  4.6  3.9   4:17.45 emacs
1780 root      20   0    5080   2796   2448 R  1.0  0.4   0:15.30 top
 456 redis     20   0   29660   3084   2472 S  0.7  0.4   0:34.57 redis-server
   1 root      20   0    5576   4208   2964 S  0.0  0.5   0:02.46 systemd

第一行:系统运行信息

该输出和uptime的输出类似。

  • 10:06:56 系统启动时间
  • 2:38 系统运行时间
  • 1 user 当前系统用户数,这里只有pysnow530一个用户
  • load average: 0.00, 0.03, 0.05 三个数据分别是1分钟、5分钟、15分钟内的负载平均值

注意:这里的负载是指某段时间内待运行任务队列长度的平均值,也就是当前等待运行的任务数。如果当前任务队列数为8,说明有8个任务已处于就绪状态,就等着CPU的时间片了。该值越大,说明系统负载越高。假设系统有一个单核CPU,此值持续大于0.7则说明系统存在问题;为1时即为满负载工作,系统已不能正常处理多余的任务;若CPU大于1,好吧,它已经忙不过来了。此时可查看系统进程,有可能是某进程出问题了。以上是一个单核CPU的情况,如果系统有两个双核CPU,则满负载时值为2x2=4,其它情况可类推。

第二行:各状态任务个数

  • total 全部任务
  • running 运行中任务
  • sleeping 睡眠中任务
  • stopped 已停止任务
  • zombie 僵死任务

第三行:cpu执行各状态时间占比

  • us 没有修改nice的进程用户态耗时占比
  • sy 执行内核态耗时占比
  • ni 修改过nice的进程用户态占比
  • id 空闲时间占比
  • wa 等待IO操作耗时占比,我们的CPU已将任务队列的任务运行完了,就等着IO了
  • hi 提供硬件中断耗时占比
  • si 提供软件中断耗时占比
  • st hypervisor从当前虚拟机偷走的时间占比

注意:如果wa过高(超过30%),一方面可能是我们的CPU太强悍了,另一方面也有可能是磁盘IO存在瓶颈。此时可通过iostat -x确认具体情况。

第四行和第五行:内存和交换区的使用信息

该输出和free命令的输出类似。

  • total 总容量大小
  • used 已使用容量大小
  • free 剩余容量大小
  • buffers 缓冲区
  • cached Mem 缓存内存,当读写文件时,系统为了提高读写性能,会将文件缓存到缓存内存。

剩余行:每个进程的信息

  • PID 进程id
  • USER 所属用户
  • PR 优先级
  • NI nice值
  • VIRT 虚拟内存
  • RES 资源内存
  • SHR 共享内存
  • S 进程状态,D表示不可中断的睡眠,R表示正在运行,S表示正在睡眠,T表示被跟踪或已停止,Z表示僵死进程,跟各状态任务个数对应
  • %CPU CPU使用率
  • %MEM 内存使用率
  • TIME+ 运行时间
  • COMMAND 进程对应命令

Python中的装饰器

本文主要讲解python中decorator的历史,然后说明decorator在python中的实现,以帮助初识decorator的pythoner能够灵活运用decorator。

装饰器模式

装饰器模式来自GoF的23种设计模式。

在设计模式中,装饰器模式的意图描述如下:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

即将附加的职责动态添加到一个对象。在扩展功能时,它比子类继承的方式要来得灵活。它是面向切面编程的一种手段。

python中的装饰器

提出

在python中,decorator最早是在PEP 318 – Decorators for Functions and Methods被提出的。

具体实现

decorator在python中形如@decorator,如:

@log
def foo():
    ...

我们将通过观察字节码,看一看添加decorator在字节码层带来了哪些变化。

首先来看函数定义产生的字节码:

def foo():
    pass

0 LOAD_CONST               0 (<code object foo at 0xb72508d8, file "<stdin>", line 1>)
3 MAKE_FUNCTION            0
6 STORE_NAME               0 (foo)

foo函数的定义对应三条字节码。

LOAD_CONST指令将pass对应的代码对象压入堆栈。

MAKE_FUNCTION将代码对象弹出堆栈,并创建一个PyFunctionObject对象,然后将函数压入堆栈。

STORE_NAME将函数弹出栈,并将它绑定到foo变量。

此时,foo变量即是一个函数。

然后我们看一下加了装饰器的函数定义对应的字节码:

@log
def foo():
    pass

 0 LOAD_NAME                0 (log) <---------- 1
 3 LOAD_CONST               0 (<code object foo at 0xb720e8d8, file "<stdin>", line 1>)
 6 MAKE_FUNCTION            0
 9 CALL_FUNCTION            1       < --------- 2
12 STORE_NAME               1 (foo)

foo函数添加一个装饰器时,对应的字节码多个两条。上面使用1、2标出。

LOAD_NAME命令是新增命令,将log函数(装饰器函数)压入堆栈。

LOAD_CONST命令将foo下的代码对象压入栈项。

MAKE_FUNCTION命令将代码对象弹出栈,并创建一个PyFunctionObject对象,并压入堆栈。

CALL_FUNCTION命令是新增命令,调用最开始压入堆栈的装饰器函数,然后将函数的返回值压入堆栈。

STORE_NAME将栈项装饰器函数的返回值绑定到foo变量。

也就是说,装饰器是一个函数,它将被装饰的函数作为输入,并将输出绑定到被装饰的函数名上。而装饰器的使用本质上就是一个语法糖。

煮个粟子

知道了它的内部实现,我们就可以动手了。

例如,实现一个打印函数耗时的装饰器:

import time

def log(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        waste_time = end - start
        print 'waste time:', waste_time
    return wrapper

@log
def hello():
    print 'hello, world'

hello()
hello, world
waste time: 4.29153442383e-05