zoukankan      html  css  js  c++  java
  • 万丈高楼平地起

    C语言

    以前刚上大一的时候,我也觉得C语言好无聊、OS好无聊,还不如学前端、Java做Web开发有趣,但是越到后面,我发现离不开底层,比如 Java里的锁、Netty库 为什么如此高效?

    一路追下去还是看到的是 OS 层,于是决定再次系统、深入、全面地学习C语言,并结合C语言去了解一些内存知识,这个时候我才发现,原来C语言就是为内存而生的,C语言的设计和内存的布局是严密贴合的,我因为学习C语言而吃透了内存,了解了计算机内存是如何分布和组织的。

    C语言无时无刻不在谈内存,内存简直就是如影随形,你不得不去研究它。

    另外一个惊喜是,攻克内存后我竟然也能够理解进程和线程了,原来进程和线程也是围绕内存打转的,从一定程度上讲,它们的存在也是为了更加高效地利用内存。

    从C语言到内存,从内存到进程和线程,环环相扣:不学C语言就吃不透内存,不学内存就吃不透进程和线程。

    自从把指针、内存、C语言吃下之后,我感觉自己瞬间升华了,达到了一个新的高度,之前的很多谜团都解开了。

    「内存/指针+ 进程 + 线程」这几个最基本的计算机概念是菜鸟和大神的分水岭,也只有学习C语言才能透彻地理解它们。

    Java、C#、PHP、Python、JS 程序员工作几年后会遇到瓶颈,有很多人会回来学习C语言,重拾底层概念,让自己再次突破。

    而且几乎你开发中用到的很多东西都是用C语言编写的,Linux、Nginx、Redis、MySQL、Git......或许你会想要探究下原理,阅读点这些开源软件的源码,那么 C 语言也是你必备的瑞士军刀。

    深入学习 C 语言,能够了解计算机底层的执行原理,是理解程序运行机制的绝佳语言,无出其右。

    在这里,不得不引用对C语言最经典的总结:

    任何比C语言更低级的语言,都不足以完整地抽象一个计算机系统; 任何比C高级的语言,都可以用C来实现。

    操作系统

    我们编程的 IDE、写出来的程序全部都需要运行在操作系统上,说操作系统是计算机软件的基石也不为过。

    操作系统是一种介于应用程序和硬件之间的软件,它管理计算机... 操作系统的专业课考试,主要考察操作系统的四大功能:进程管理内存管理文件管理IO管理

    程序运行起来就需要创建进程,这涉及到操作系统的进程管理;写程序需要定义变量、存储数据吧,这又涉及到内存,对应内存管理;有时候我们还需要读写文件,这又离不开和文件系统打交道;你需要学习使用锁、条件变量、临界区来控制程序并发执行时不会错乱。

    而读写文件、分配内存这些又离不开系统调用(System call)。

    并且真正做起工程就会发现,很多问题是和操作系统紧密相关的,不理解操作系统,你连问题的原因都分析不出来。

    比如前段时间我们出现的在基于协程(libco)的框架下,使用多线程的锁去做同步互斥偶发死锁,后来分析才发现原因:

    协程是应用层实现的,一个线程内多个协程对于操作系统是感知不到的:

    img

    那么当一个协称 A 上锁后发起网络 IO 请求,这个时候会被切换到另外一个协程B,而协程 B 又去请求这个锁。

    那么这个时候操作系统会认为这个锁已经被上了,会将协程 B 对应的线程挂起到等待队列,这样的话就导致协称 A 永远无法运行,也就无法释放锁,导致死锁。

    解决的方法也很简单,就是将锁设置为可重入锁,可重入意味着同一个线程多次去请求同一个锁不会导致挂起。这样当协程 B 再去请求锁的时候,操作系统就会认为协程 B 所在的线程已经持有这个锁了,直接返回,继续执行。

    总之,我们写程序每时每刻都在和操作系统交互,没有理由不学好。

    编译原理

    编译原理可能是我们平时接触得最少的了,大家也许会觉得自己又不用去造新的编程语言,学编译原理干啥。

    学好编译原理有啥用?

    你会站在更高的角度去审视这些编程语言,看到的不再是表面的语法,更会想到语法背后的实现。

    这种感觉很透彻,就像搞懂了操作系统、体系结构你会明白一个程序从双击鼠标开始,到底是如何被运行起来的,这种掌握一切细节,透彻的感觉,真的很奇妙,不信你去试试。

    说人话!

    那学了编译原理你能干啥?

    当你学完有限状态机以后,你会发现以前觉得很牛逼正则表达式似乎自己也能用 DFA、NFA 实现一下了。状态机的思想在编程中很多地方都用得上。

    比如解析 HTTP 协议,如果没学过状态机思想,你可能会一行行的 if/else 去做解析,这里最麻烦的地方在于,if/else 需要提前将 HTTP 头部字段都接收到再来判断,而我们知道 HTTP 基于 TCP,而 TCP 是流式传输,所以你很有可能是几个字符一组组接收到的,这个时候用 if/else 写出来就很难看了。

    而用状态机编写起来代码就会非常优雅。状态的转移是由规则驱动的,接收到一个字符就判断一个,非常的方便。

    继续学完语法分析,你会掌握递归下降分析这样非常重要的思想,你可以使用递归下降快速的实现四则运算计算器。

    如果不用递归下降你可能需要先中缀表达式转后缀,然后求值,这是我们大一数据结构课写的,当时用栈写的,有点麻烦。后来学完编译原理,又用递归下降重写了一遍,区区几十行代码遍搞定。

    还有一类场景在实际开发中的用的很多,比如淘宝、京东这样的电商,它们的营销规则有很多,比如满减、直减、跨店等等,这样的规则是不可能写死在代码里的。

    那是怎么做的呢?

    一般会实现一个配置系统,并设计一个DSL(领域特定语言)来表达这些规则,将规则直接配置到系统中,这样可以非常方便的修改,那么如何在代码里去解析 DSL 定义的规则呢?这就需要为 DSL 写一个语法解析器,这里就会用到语法分析的方法。

    DSL(Domain Specific Language),它是一种用于某个特定领域的程序设计语言。这种特定于某个领域是相对于 C、C++、Python 这种通用语言而言的,通用语言可以在各个领域使用,我们熟悉的大多数程序设计语言都是通用语言,它们都是图灵完备的。

    像我们平常经常使用的 JSON、SQL、HTML 这些都算是一种 DSL,你甚至可以尝试用递归下降去写一个 JSON、XML 解析器,这比写电商网站更有价值的。

    继续往下学你会了解到抽象语法树 AST 如何生成、如何转化为中间代码、如何对中间代码优化、最终又是怎么生成机器指令的。

    你会看到贪心算法在寄存器分配中的应用,也会看到图论中的可达性分析又是如何实现死代码消除。

    IDE上面那个绿色的编译按钮对你不再是黑魔法。

    为啥点一下就能生成可执行的程序?

    你写的英文字母又是如何变成一个个二进制指令的?

    学完编译原理,这些通通不是问题~

    当然完成一个像 gcc、Clang 这样的编译器难度太高太高,我们学习编译原理的目的也不是去造这样的轮子,而是为了更好的理解和运用编程语言。

    体系结构&组成原理

    上面说的都是软件层面,体系结构则是关于计算机是如何工作的,你会了解到典型的存储程序计算机是怎样运转的。

    ”我们不是学习使用计算机的,而是学习如何造计算机“,造计算机有点夸张,但是至少我们得了解计算机的实现原理,了解计算机的各个部分是如何协调工作的。

    我们说计算机中一切都是0、1,0、1又是通过高低电平来表达的,通过与、或、非等逻辑门电路来表达二进制的数值运算,再将这些简单的电路集成在一起,就形成了ALU等具有运算能力的处理器。

    你会了解到一条指令是如何被 CPU 执行的,CPU 从内存或 Cache 中取出指令,放入指令寄存器,并对指令译码。译码就是按照指令的编码规则,将指令拆分成一系列的微操作和操作数。然后发出各种设备控制指令,执行微操作。这样就完成一条指令的执行。

    我们说学完编译原理,你能够明白我们写的英文代码是如何被变成二进制指令的,学完操作系统你能搞懂,二进制程序是如何被链接在一起,又是如何被操作系统加载、执行的。而组成原理则会告诉你二进制指令是如何控制电脑的,我们的操作系统本质上也是一个二进制的程序。

    你理解了计算机存储层次结构,理解了多级 Cache,你就会通过优化数据访问方式来编写出速度更快的程序。

    你会学到底层体系结构对 C 等语言的栈帧和参数传递的支持,参数是如何被传递给另外一个函数的?函数的返回值又是如何拿到。

    这是学习组成原理对于写代码的意义。

    为什么说这些是基础?

    因为你会完整的看到写的代码如何变成二进制指令,又是如何去控制各种门电路,最后变成屏幕上花花绿绿的程序的(当然这里可能还需要学习显示器的原理),这就是我们常说的“基础”和“原理”。

    计算机对你不再是黑盒,这将成为你以后的核心竞争力,否则作为科班毕业生如果只会使用 Redis、Mysql、Spring 来写各种网站,那么大学四年的学习如何体现呢?

    数据结构与算法

    数据结构和算法你能在任何计算机领域里看到,比如:
    在编译原理中寄存器的分配会用到贪心,死代码检测与消除会用到图论里不可达的知识;

    操作系统进程、线程调度会用到多级队列和调度算法;组成原理中 Cache 的替换会用到 LRU、FIFO 等算法;

    开发必备的数据库也离不开B+树、LSM 等数据结构和查找算法。

    很多时候我们需要的算法都被封装到编程语言的基础库里了,以至于很多同学会觉得算法离我们太远,其实不是的。

    如果不学习算法,连什么时候用 Map(红黑树实现)、什么时候用 HashMap 都分不清。

    所以学习算法有助于我们根据应用场景选择最合适的数据结构,可以说不学算法的工程师一定不是一个优秀的工程师。

    技能

    VSCode、Jetbrains 全家桶这些 IDE,文档编写 Markdown、Git 等版本管理工具。 SSH 远程登录、端口转发,Ngrok 内网穿透等等这些提高你开发效率的工具,都算是技能,平时用到多学习多积累就好了。

    我只提一点,尽早使用 Linux、类 Unix(Mac)作为主力开发电脑。 我大二的时候,就是看了王 ying 的那篇《完全用 Linux 工作》,直接买了个 SSD 套上 U 盘外壳,做了一个启动盘,后来用了将近一年的 Ubuntu,只有在选课、提交作业等需要用的 IE 浏览器的时候才会打开 Windows(这里不得不吐槽学校老古董网站!)

    友情,恋爱,推理,因为有当初的约定才努力不懈。
  • 相关阅读:
    HDU 5360 Hiking(优先队列)2015 Multi-University Training Contest 6
    多区域显示(6)-版面布局
    静态变量和成员变量的区别 && 成员变量和局部变量的区别
    java基础学习_面向对象(上)02_day07总结
    java基础学习_面向对象(上)01_day07总结
    面向对象的概述
    面向对象思想的引入
    Failed to create the Java Virtual Machine(zt)
    eclipse web开发Server配置
    javamail接收邮件(zt)
  • 原文地址:https://www.cnblogs.com/ziyang1060/p/14948681.html
Copyright © 2011-2022 走看看