登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Code@Pig Home

喜欢背着一袋Code傻笑的Pig .. 忧美.欢笑.记忆.忘却 .之. 角落

 
 
 

日志

 
 

我(码农)的知识体系结构  

2013-02-26 21:11:20|  分类: 唧唧歪歪 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

我就一码农,学名程序员。农民伯伯靠种地为生,我靠种代码为生;土地里长出了庄稼,键盘中敲出了程序。毕业,进一游戏公司,从业六年半,干了五年服务器,一年半客户端。主要在PC上折腾,服务器弄弄FreeBSD,客户端还得跟着M$老大的Windows混。敲了这么多代码,也尝试总结下知识,斗胆称之为体系结构。

计算机体系结构/硬件(PC/PS3/Wii/iPhone/Google Glass)

几十年前,冯·诺依曼与图灵哥哥弄了点理论体系,种下来计算机的种子。如今,计算机中总有个CPU,用来计算的;还有内存、硬盘,用来存储的;还得加上个显卡,否则无法玩游戏;把前面几个东东都插到主板上,再接个显示器、鼠标、键盘,最最标准的 IBM PC 就出来了。后来有了 USB 接口,U盘诞生了;再后来弄个RJ45接口,就可以上网了;上网还要接网线,好麻烦,于是有了wifi。

CPU自己有一些寄存器(register),访问起来最快。CPU和内存间的交互总觉得还不够快,所以弄了L1/L2 cache。

反正访问速度是 register > L1 > L2 > memory > harddisk/usedisk。

CPU就是一吃货,只负责吃数据(处理数据),每次先找 L1 cache 拿数据,不在 L1 cache 的,再找 L2 cache 要,又不在 L2 cache 的,才找内存要。找数据找不到这事,叫 cache-miss。要是内存中也找不到咋办?那不是CPU管的事,操作系统同学负责揽这活儿。

除了标准的IBM PC,其实还有大型机(这哥们有好多好多cpu,好多好多内存)、单片机(51单片机,要写汇编的哦)。不过这年头,原来是单片机的地方,现在都是台嵌入式PC了,硬件太tm便宜了。

还有就是各种游戏主机,啥PS2/PS2/GameCube/Wii,都是标准IBM PC的变种,为了更好的运算、图形能力而设计的计算机。不过这些哥们最近都不好混了,因为iPhone出来了,普通PC的运算、图形能力也越来越强大了,写游戏的码农们根本用不完这么多硬件资源,不需要再专门设计游戏主机了。最近PS4的发布会,就发现其已经长得很像PC了。Valve马上就要出Steam Box,丫就一PC。

还有现在智能手机、平板满天飞,PC的结构在以各种形式渗透到生活的每一个角落。Google Glass马上就要开卖了,《七龙珠》里面贝吉塔带的、测量战斗力的眼镜,很快就要变成现实了。

操作系统(Windows/Linux/MacOSX/iOS/Android)

有了硬件就要有软件,计算机需要一个大管家,才能把上篇那一堆CPU、显卡、内存啥的都管理起来,让它们工作。

其实早期的操作系统都没那么复杂,最简单的就是 51单片机,可能就直接写汇编控制下CPU就好了,我没玩过。

后来硬件复杂了点,嵌入式里就出了 ucOS。作者写了个抢占式多线程调度系统,然后写了本书,再卖书送代码,火了~

而 IBM PC 配上了 MS-DOS,步入千万家,把 Microsoft 养肥了。

之后 PC 越来越复杂,我要看图形界面(不要命令行)、我要玩3D游戏(要有显卡)、我要U盘、我要上网,各种需求。操作系统也就随之越来越复杂。

大管家先要管理 CPU,而且 CPU 速度还贼快,一次只干一个事情,有些浪费。所以要有进程调度子系统(process schedule subsystem),进程A从磁盘读数据的时候,可以让进程B干活,不浪费 CPU 运算资源。有了一堆进程,进程间就得通讯啊,通讯就需要 memory copy,有时候数据量大了,通讯成本太高咋办?那就在进程中再搞个线程(thread),线程可以共享进程的数据,直接访问,不需要通讯了。不过允许多线程同时访问同一份数据,又带来了同步的问题(synchronization),就有了mutex、semaphore。但锁机制还有性能开销呀,咋办?特定的情况下,还可以利用 CPU 的 CAS 指令搞 lock-free 的数据结构。

管了 CPU 还得管内存,于是有了虚拟内存子系统(virtual memory subsystem)。从进程的角度来看,要简化内存操作,进程A和进程B都访问相同虚拟地址(virtual address),实际它们访问的物理地址(physic address),是不同的。现代 CPU 都把虚拟地址到物理地址的映射做到硬件上了,所以操作系统必须的有虚拟内存子系统。

光管内存还不够,电源断了,数据就没了,所以还得把数据写到磁盘上,于是有了文件子系统(file management subsystem)。硬盘/U盘,只是张白纸,如何规划数据的格式呢?那就要提供文件系统格式,比如 Windows 的 FAT32/NTFS、Mac OSX 的 HFS+,这些也属于文件子系统管。

数据能存储了,还得将其显示出来,那就得用显卡。而显卡品牌多多,操作系统也不知道会有哪些牌子,那就设计个 PnP 系统,把 PCI、USB 等插槽管理好,然后让显卡厂商去写驱动(driver),自己管理自己的显卡硬件。网卡也类似。键盘、鼠标就标准得多,通用驱动即可,不需要生产厂家写。

这年头没有网络不行,所以还得有网络子系统(network subsystem),俗称协议栈(network stack)。负责实现 TCP/IP 那一坨东西。

编译器(GCC/LLVM/VC++ Compiler)

最早的程序,是直接写硬件指令的,但指令不好记,人们就弄出个汇编语言(Assembly Language),用于助记。把汇编文本转换为机器语言的转换器,就是汇编器(Assembler)。

但程序规模越来越大,直接写汇编还是太辛苦,所以就再设计些高级语言出来,最著名的就是C了。编译器(compiler)先把高级语言源文件转化为汇编,再通过汇编器变为可执行程序。那可执行程序的格式长啥样呢?

每个操作系统,会定义自己的可执行文件格式,内部结构简单可分为数据段、代码段,文件执行后,操作系统根据格式的信息,加载到虚拟内存的不同位置,然后交给CPU执行。Win32下的可执行格式为PE,而Linux下面是ELF

编程语言(C/C++/Go/Java/C#/Erlang/Lisp/Scheme/Haskell/Python/Lua)

高级语言中最著名的是C,也是我认为设计得最简洁的语言之一。C伴随着Unix共生,并一路发展,既可编写操作系统、编译器、驱动程序,也可编写业务逻辑。

不过毕竟设计C的那个时代,C主要是用来写操作系统、编译器,是面向底层的高级语言,用其写高层次的业务逻辑,程序规模大的,会很蛋疼。需要写代码之人关心内存管理,就是万恶之源。

C对于大规模的程序,多人协作起来,不是那么方便,于是有了 C++,在 C 的基础上,设计了OO、封装的语法,让多人合作更便利,但也因为设计理念,留下了很多复杂的语言细节,让人蛋碎了一地。不过 C++ 这么流行,完全是 M$ Windows 独占天下,共生共荣的。

上面说到手工内存管理是万恶之源,于是 Sun 在 C++ 的基础上更进一步,设计了 Java。Java 是面向业务逻辑的语言,抛弃了很多与底层的联系。而且本身设计为 VM + Opcode 的结构,让编写一次到处执行成为可能。M$ 看着眼红,设计了 C#,紧跟步伐。经过多年发展,Java/C# 成为企业应用开发的主流语言。

Lisp 属于函数式语言的鼻祖,曾经的辉煌,在缺少强力软件公司的支持之下,慢慢没落。除了少量还在维护中的大系统,新的系统已很少看到这门语言的身影了。而且 Lisp 的标准化不完善,网络库这么一个基础库,也是非标准的。这种不标准,让 Lisp 在应用开发上举步维艰。Scheme 是 Lisp 的小弟弟,只用于教学,最近也被 Python 替代了。

Haskell 算是继承 Lisp 衣钵、目前还算流行的函数式语言。不过缺乏大厂商支持,注定了其只是 geek 的玩具。

Java/C# 虽然是 VM + Opcode 的形式,但还是把编译和执行两部分开了,所以写了代码总还得先编译,然后执行。Python 就在此之上更进一步,把编译作为执行期的前奏,自动完成,让开发效率再上一个台阶。加之 Python 简洁的语法,也颇受一些人的喜爱。

Lua 是披着 C 语法风格的函数式语言,设计理念与 C 类似,简洁、再简洁,最早的设计目标就是用于嵌入式。在 WOW 火了之后,Lua 也就火了。

现在是多核时代,会大量使用多线程设计,但传统的锁的共享数据的方式,让写代码之人十分痛苦,也很容易出错。Erlang 虽然不是一门很新的语言,但当年选择了 send-message 的方式作为数据同步方式,彻底抛弃锁,让码农不在接触锁,切合目前的主流发展方向,这两年也大红大紫了一把。不过 Erlang 的那套函数式语法,让很多从 C 过来的码农很不适应。

最后说一下 Go,我认为 Go 是继承了 C 简洁的设计风格,而且面向应用开发的语言。未来,服务端本来需要 C 开发的模块,大部分都可以由 Go 的代替。Go 是否能最终与 C 一样流行,就看其在 Google 整个战略上的地位了。

数据结构(Array/LinkedList/HashTable/Stack/Tree)

数据结构其实没啥好说的,每天最常用的就是数组(array)、链表(linked-list)、哈希表(hash-table)。栈(stack)和树(tree),写某些算法的时候才会用。

基础的原理懂了之后,再根据手上使用的语言,深入研究其提供的数据结构的实现原理,用这些类库的时候,心中有谱即可。比如 C++ STL、Java Collections。

领域知识(游戏开发/ERP/web)

作为应用开发的码农,最终每天接触的,还是这一层面的知识。我个人主要从事游戏开发,谈谈这个。web略懂,ERP不懂,不谈了。

游戏开发一般分为客户端、服务端两部分。

服务端,负责数据存储、网络管理、玩法逻辑等等。

数据存储,指一个玩家会有一些数据,如HP、MP、等级等等。这些东西要存储,乍办?MySQL、文件数据库。如果高效管理呢?异步I/O、binlog、独立的db server。

网络管理,服务端还要同时管理几千号的socket连接,这涉及网络模块。如何高效?epoll/kqueue自然要用,然后独立的 recv/send thread等等。

玩法逻辑,比如:玩家升级任务、周末活动等等,这些业务繁杂、逻辑众多,但也只能根据需求见招拆招,你对开发的游戏越热爱、越熟悉策划的设计,这部分的工作越能做好。用 C/C++ 写这些逻辑,就很想死。所以很多公司采用 Python/Lua 等脚本语言来负责这部分。再进一步,就是归纳出共同点,形成玩法模块,让策划填写xls表,生成数据,码农不再需要写太多代码,比如:奖励模块就是很通用。

客户端,负责游戏的显示。就我个人的经验而言,3D游戏,客户端核心代码要比服务端多很多,复杂很多。

3D游戏,至少需要一个引擎,渲染、物理、声音、网络、GUI等等,各个模块,每个模块都不是省油灯。

渲染,从最底层API(dx/opengl),到上层模块,如模型、场景、特效、材质。这一部分是3D引擎的大头。

物理,物理系统目前国内用得不多,大多也是嵌入开源或商业的现有系统,自己写太费精力,划不来。

声音,简单的可以自己写写,封装下dx api即可。复杂的就用 fmod 之类,都可以满足需求了。

网络,客户端网络部分就比较简单,只要管理一两个socket连接。一般与服务端共用一套底层网络模块即可。

GUI,界面系统对于游戏逻辑来说,除了场景、模型之外,界面是玩家接触得最多的。一般界面系统都是自己设计,效率和效果都可以自己把控,开源的如 CEGUI,效率是个问题。

玩法逻辑,因为客户端不存在数据存储的问题,这部分也都是如何表现策划的需求,比如释放技能、升级界面、炼化界面等等。与服务端类似,也是抽象共同点,尽量形成策划填写xls表就可以搞定一个玩法的方式,比如 物品系统。

  评论这张
 
阅读(1925)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018