-
- 2013-11-01
- 技术
Python包管理不同方式的区别
学习Python已经有一段时间,经常会遇到安装各种包的问题,一会
setup.py
, 一会easy_install
,一会又是pip
,还有一些概念比如distutils
,setuptools
等等,搞不清楚谁是谁,什么时候应该用什么,今天就把这些概念 澄清一下。distutils
distutils是Python标准库的一部分,其初衷是为开发者提供一种方便的打包方式, 同时为使用者提供方便的安装方式。
Read More ... -
- 2013-10-26
- 思想
为什么我们需要数据结构
最近在学习各种数据结构,于是就在想,为什么我们需要数据结构呢? 为什么要设计这么多数据结构?数据结构到底解决了我们什么样的问题?
我们提到 数据结构 时,一般是指计算机科学中的一个概念, 但是从本质上讲,数据结构应该是指对数据的一种组织方式。既然如此,我们没必要非在计算机科学领域中讨论 概念本身,把它放在其它领域中,可能更能加强我们的理解。
就说图书管吧,假如你是一名很久很久以前的图书馆管理员,那时候根本没什么计算机。数据结构?那是什么?
你的任务就是看着图书馆里的一堆书。于是,有一天,图书馆来了一堆书,你把他们堆成一堆,放在馆里。 这时候,有人来借书了,他只能在那一堆书里乱翻,翻来翻去也找不到自己想要的书,因为那是一堆书, 有的书他检查了很多次,有的一次也没检查。
这时候这堆书是一个集合,不方便遍历。
时间长了,抱怨的人很多。
作为一个怕麻烦的管理员,你忍受不了别人的抱怨,于是,你把那 一堆书 变成了 一排书。
这下好了,来找书的人,只要从书架左边走到右边,按顺序找就好了。只要书在图书馆里,慢慢找总是可以找到。 但是,随着图书馆的书越来越多,这样找实在是太慢了,因为每次都要从第一本书找到最后一本书。
这时候这堆书是一个列表,方便遍历,但是不方便查找。
时间长了,抱怨的人很多。
作为一个怕麻烦的管理员,你忍受不了别人的抱怨,于是,你把那 一排书 变成了 很多类书。
那么,按什么分类呢?按书的大小么?颜色么?退一步讲,分类的依据是什么?
分类是为了加快读者查找书的速度,那么读者查找书的时候,是按什么查找呢?是按书名。所以,我们对书名分类。 按书名分类也有许多种,按书名读音么?按书名笔画吗?按书名字数么?我们很容易想到,按读音分类给读者的压力最小, 也就是查找前的开销最小。否则每次找书之前还要数一下笔画,读者一定又会抱怨。
这时候,我们按读音把书分类,书名第一个字是A的在A书架,是B的在B书架。这下读者查找书的速度大大加快了, 因为一下子就能排除那么多类书,而代价仅仅是想一下书名第一个字的读音。不过,我们马上又发现,有的书架上书实在太多了, 那有什么关系?这个问题我们解决过啊,只要再分类就好了,书名第一个字我们用过了,现在用第二个字。
读者终于大致可以满意了。
这时候这些书架构成了一个查找树,方便查找。
另外,我们注意到,其实对于管理员来说,他的负担是增加了的,比如新来了一本书,如果图书馆是一堆书, 只要把新书扔在那一堆里就好了,如果是一排书,要把新书放在这排书的最后,而如果是分好类的书架, 管理员就要先找到这本书的位置,再把新书放在那儿,而不能随便放。好在分类后,我们找新书位置不会花多久, 假如分好类后,读者查找书方便了,但是管理员要把新书放在合适的位置,需要花一年时间, 那这个分类的方法肯定不是一个好方法。
这告诉我们
维护数据结构很重要。
这时候,我们在不知不觉间居然
设计了一个数据结构
这时候,我们回到开始时的问题,为什么我们需要数据结构?对应上面的故事, 为什么我们要把一堆书变成多类书?简单地说,这样可以使找书的过程变快。 这正印证了维基百科词条中的那句话。
数据结构是计算机中存储、组织数据的方式。通常情况下,精心选择的数据结构可以带来最优效率的算法。
回头想想,从一堆书变成多类书的过程,其实就是数据的组织方式发生了变化。我们来抽象一下整个过程。
- 我们有一堆数据D。
- 数据上最常用的操作是O。
- 我们的目标是让O很快。
- 我们设计一个数据结构S来组织数据D。
- 数据结构S需要额外的信息EI来组织数据D。
- 数据结构S有性质P,性质P可以使操作O很快。
- 数据结构除了支持操作O外,还要支持两个最基本的操作,Add:添加数据,Del:删除数据。
- 数据结构要保持性质P,所以Add,Del需要额外操作EO来保持P。
那么,关键的地方就在于:
根据操作O,找到性质P,设计数据结构S,使S有性质P,同时使额外信息EI,额外操作EO尽量小。
所以,无论是设计数据结构还是学习数据结构,都要弄清楚,
- 数据结构的关键性质是什么
- 为什么关键性质可以加快操作
- 额外信息与额外操作大小如何
下面我们探讨一些基本数据结构的特点
数组:数组的关键性质在于元素位置可以通过简单计算马上得到,这个关键性质为随机访问提供了很大的 便利。如果数据大小需要动态扩展,那么使用数组是不方便的,因为动态扩展难以维护数组的关键性质。
数组之所以拥有“元素位置可以通过简单计算得到”这个性质,在于数组在内存中是一片连续的区域,这样 知道数组第一个元素位置,知道每个元素大小,通过一次加法,一次乘法,就可以知道第N个元素的位置。 如果数组需要动态扩展,如果这片连续区域相邻的地方有可用内存,那么额外操作是分配这块区域给数组, 如果相邻位置没有可用内存,需要另找一片足够大的连续区域,作为新数组的位置,同时还要把已有数据 复制过去。
Read More ... -
- 2013-10-25
- 技术  c语言  计算机系统
字符指针与字符数组真正的区别
问题缘起
先看一个示例
示例1
#include <stdio.h> int main() { char *p = "hello"; char q[] = "hello"; printf ("p: %s\n", p); printf ("q: %s\n", q); return 0; }
上面的例子会给出这样的输出
p: hello q: hello
这样看,
char *p
和char q[]
好像没什么区别, 那么我们再看一个例子示例2
#include <stdio.h> int main() { char *p = "hello"; char q[] = "hello"; p[0] = 's'; q[0] = 's'; return 0; }
如果你在Linux下,运行时可能得到这样的结果
Segmentation fault (core dumped)
这时候你看到了区别,出现了段错误, 你一定想明白,到底发生了什么, 经过几个小实验,你可能会发现使用
char *p
定义时,p指向的数据是无法改变的。 然后你Google, 别人可能会告诉你- char 指针指向的数据不能修改
- char 指针指向的数据没有分配
- ...
你听了还是一头雾水,不能修改是什么意思,没有分配?没有分配为什么能输出?
作为一个好奇心很重的人,你是绝对不能容忍这些问题的困扰的,且听我慢慢道来
Read More ... -
- 2013-10-24
- 工具
为什么使用 Markdown
- 看上去不错
- 既然看上去不错,为什么不试试呢
如何使用 Markdonw
1. 标题级别
效果
一级标题
二级标题
三级标题
代码
# 一级标题 ## 二级标题 ### 三级标题
2. 列表
效果
- 列表1
- 列表2
- 列表3
代码 (注意星号与文字之间的空格)
Read More ...* 列表1 * 列表2 * 列表3
-
- 2010-09-17
- 操作系统
关于《自己动手写操作系统》的总结
昨天晚上终于完成了《自己动手写操作系统》的最后一部分功能,看着三个控制台上的进程各自运行着,终于舒了一口气。查看了最早的程序,是8月18号的,到现在整整30天。原本以为用10天可以搞定,没想到会用这么久。这本书读起来非常累,尤其是要照着书上写的东西把所有程序自己敲一遍,然后调试,运行,周而复始。虽然只是实现了一个最最最简陋的操作系统,没有文件系统,没有内存管理,没有命令,没有好多,不能像正常系统一样工作,但对于我这样的初学者,即使是完全照抄,还是费了很大的劲,当然,也收获了很多。所以,要总结一下,为这段日子画一个句号。
首先,评论一下这本书。《自己动手写操作系统》的作者于渊,没有查到他更多的信息,只是根据《程序员》杂志主编孟岩在序中的介绍,于渊是一位非常年轻的程序员,有着广泛的技术视野和上佳的文笔。年轻是一种资本,从书中也可以看到作者的活力与激情。当年Linus写出Linux的内核时也不过是大学二年级的学生。这就是年轻的好处,有着不断的激情与梦想,有着无限的精力,除旧布新,开天辟地。年轻就是要不断探索,所以整个学习过程,我深受感染。但是年轻的劣势就在于沉淀的太少,所以书中很多问题,作者并没有交代清楚,整个思路也没有那么清晰,精要。经典的书籍,一定有一种道在里面。当然,这种评论首先出于我自身的理解和悟性,并不是书本来就是这样的。于渊自己也说,这本书是他学习过程的记录和总结,他也是以一个学习者的态度来写书的。所以,这一切都不是问题,万事都有开始,Linus当初为访问学校文件系统而编写磁盘驱动时,恐怕也没有想到他会开辟Linux世界的大好河山。
在学完整个学期的操作系统课程后,如果你想自己写一个小的操作系统,一定会发现无从下手,因为传统的操作系统课程过于关注理论,不会告诉你要用什么工具,什么语言,如何写代码这些。当然,这并不是说理论不重要,在你对事物有了一个感性认识后,会发现理论有非常重要的作用,因为理论基础不行,会在很大程度上制约你的理解和进步。比如我现在很头疼的一点就是自己的数学基础太差了。既然要动手写,就有一个开发环境,这本书给我很大的一个收获就是在各种工具的使用方面。所以就从这儿说起。
三种操作系统:学习这本书的过程,我使用了三个操作系统,主机用的是windows,然后虚拟了DOS和linux。在开始阶段用Windows写程序,然后共享到DOS下面运行(因为那些程序要在实模式下运行)。中间阶段以及后期把程序所在文件夹共享到三个系统里。在linux下写程序,编译,然后把程序写到虚拟软盘映像,然后在DOS下加载虚拟软盘映像观察效果,如果有问题,在linux或windows下调试。其实整个过程都可以在linux下进行,并且在这本书的第二版里,作者已经把工作环境完全 放在了linux下,并对此作出了说明。linux命令行的工作方式,会很大程序上提高工作效率,这一点我已经深有体会,不仅如此,那些神奇的命令单兵作战或者协同作战会起到你在windows下想做而做不了的事。也许在windows下可以通过各种软件实现那种功能,但是在linux下,那些命令从发明到今天,20多年了,大家还在使用,不论时代怎么改变,人们都有共有的需求,所以那些命令永远不过时,并且越来越强大。我说上面这些,并不是想让你用linux,我觉得不论什么操作系统,它的存在必然有他的理由以及生命力所在,只有适合不适合,没有高下之分,这正如各种编程语言一样。人是不能被说服的,只能自己觉悟。如果不主动探索,永远不知道原来外面有一个大大的世界。
三种虚拟机:因为需要不同的操作系统,所以有人发明了虚拟机这种东西,可以虚拟出不同的操作系统,以便人们不用再买一台机器,不用多系统,也能在各种操作系统之间自由切换。这就是操作系统课上老师说的一台物理设备抽象出了多个逻辑设备吧。学习这本书的过程,我使用了三种虚拟机:VMWare,Virtual PC,Bochs.VMware功能强大,也挺消耗资源,我用来虚拟linux,然后直接在上面写程序。Virtual PC小巧,占用资源少,我用来虚拟DOS,Bochs是一款开源软件,在windows和linux下都有对应的版本,因为它是用软件模拟了硬件,所以很慢,但是它的一个很大的优势也在于此,Bochs可以用来方便的调试操作系统,你可以用它看看一台计算机从加电开始,都执行了哪些指令,各种寄存器的值怎么改变的,例如你怀疑自己的内核有问题,那么可以在内核的入口处设置一个断点,虚拟的计算机启动后,到内核的入口用就停住,你可以看看各个值是否正确。并且三种虚拟机应该都有专门的机制和主机共享,VMWare Virtual PC 的共享我用过,bochs不经常用,就不知道了。
三种编译工具:nasm,gcc和make。nasm是开源的汇编语言编译器,windows和linux下都有相应的版本,gcc就不用说了,linux下经典的编译工具,对这两种编译工具,整个过程也只使用了它们最基本的功能。make是我第一次接触,下面说一下make的作用。因为要编写一个操作系统,即使它十分简陋,但是还是要有许多文件需要编译,这些文件分布于不同的文件夹,需要的头文件也在不同的文件夹,难道每次都要一个一个地重新编译吗?出于这样的需求,出现了make,使用make,只要第一次用一种格式化的语言写一个make file,定义好make 命令的作用,然后每次更新完文件,只要简单修改一个Makefile,然后输入 make **,所有文件就会自动全部编译完成,并且如果文件没有更新,就不会被重新编译。
三种编辑器:edit,notepad,vim。因为受之前学的《汇编语言》的影响,开始的时候,使用的是DOS下的edit编辑程序,后来感觉实在不好用,就干脆直接用记事本了。学习过程到了中后期,改用了vim。用过linux或者unix的人一定不会不知道vi。vim是vi的一个升级版。vi是许多unix,linux系统默认的编辑器。vim和emacs,分别被称为编辑器之神和神的编辑器,它们的地位可想而知。这次学习操作系统的过程,vim的使用给了我很大的感触,这真的是无比强大的编辑器!每次当我想到,如果有这么一个功能多好,然后google vim+想要的功能,居然每次都可以找到。原因就在于你想要的功能,前人都想到了,所以,利器在手,就看你能不能玩转了。而且因为是开源,vim有着很好的扩展性,需要一个功能时,加入对应的插件就可以了,根据需要定制,非常方便。另一个感触是,学习一个工具,一定要用它,这样才能不断进步。之前我也学习过vim,可是只是为学而学,不是为用而学,所以学到的东西很快就忘了。包括整个Linux系统也是这样,一定要去用它,不要为了学而学。并且vim的学习曲线陡峭,开时时候非常不适应,但是过了适应期,你会发现vim是无往不利,真正的编辑器之神!
N种小工具:学习的整个过程,还用到了N种工具,这里一起说一下。windows下用到了Turbo Debugger,一款古老的调试器,用来调试汇编程序。winimage,用来建立虚拟软盘,同时可以向软盘里写入文件。Unltra Edit,这本来是一个著名的编辑器,被我用来当16进制查看器查看虚拟软盘的16进制值了。。。linux下我最常用的工具是grep。这是个非常有用的小命令,当你想要知道一个变量都出现在了哪一个文件的哪一行时,你难道像在windows里一样一个文件一个文件的点开看吗?有了grep,只要一个命令就可以把他们全部找到了。如果你想对所有文件中的一个变量作出改变时,就用到了另一个命令,sed。这个命令可以批量的替换,删除你指定的一个或者一批文件中的某个变量。非常方便。有一次,我想在每一个#include "global.h",前面加一个#include "tty.h",并且换行时,就用到了这个命令。还有一个最常用的工具是ctags,这个工具配合vim使用,给我阅读代码带来了很大的方便。ctags的使用是这样的,先用ctags -R *,生成一个tags文件,里面记录了你所有代码中用到的变量,函数等等。这样当你想从一个函数的调用处跳到它的定义处时,只要Ctrl+],主可以直接跳过去了,然后Ctrl+O又跳回来,或者你面对那么多文件,忘记了main函数在哪里时,只要vim -t main,就直接进入了main函数,非常好用。
工具就像兵器一样,好的工具可以让工作变得非常有效率,关于工具,说的不少了,就说到这里。
因为学习的是操作系统,下一个话题就说一下在操作系统方面的收获。
在操作系统上,这本书和课上学的操作系统课不一样的地方在于,它首先给了我一个感性的认识,让你觉得操作系统是可以看的到,摸的着的,而不是课堂上抽象出的一些概念。比如进程一章,就真正在操作系统中编写了进程并让它们运行起来。我觉得感性的认识加上理论上的思考才是最有效的学习方式。实践,然后知道不足,去学习理论,然后再实践,然后觉得知识又不够用,然后再学习,这样一个螺旋式上升的过程我觉得应该是有效的。这是在方法上给我的启示。在具体的知识上,主要实现了从CPU加电初始化BIOS,加载引导扇区开始,到加载loader,loader加载kernel,然后kernel设置中断,键盘驱动,初始化进程,然后由进程调度程序调动整个进程运行这一系列的流程。其中还学习了保护模式,GDT,LDT,IDT,8259A等等概念及其运用。但是没有涉及处理机管理,内存管理,文件系统这些东西,在这本书的第二版《Orange's 一个操作系统的实现》,已经有了这部分功能。
说了也不少了,没有想说的了,就作一个下一步的计划吧,下面要重新学习一下C语言和汇编,感觉基础还是不行,然后散着看一点操作系统方面的东西,跟着课学一下理论,好好看看 Operating system concept,理论了解了,可能会看《操作系统:设计与实现》以及Linux的源代码。未来的变数还很大,只能有一个初步的打算了。
Read More ...