当前位置: 首页 > article >正文

Unix/Linux | A Programming Guide

注:本文为 “UNIX / Linux 教程” 相关文章合辑。

略作重排,如有内容异常,请看原文。


UNIX / Linux Tutorial for Beginners: Learn Online in 7 days

By : Emily Carter

UpdatedFebruary 5, 2025

UNIX / Linux Tutorial Summary

Linux is the most popular server OS. Linux is a clone of UNIX. Knowing one is as good as knowing the other. In this UNIX / Linux tutorial for beginners series, we will be using Linux as it’s freely available. The training will require you to execute certain commands. Make sure to practice them!
…Linux 是最流行的服务器操作系统。Linux 是 UNIX 的克隆版本。了解其中一个就相当于了解另一个。…

Prerequisites for learning UNIX / Linux Tutorial?

Nothing. This Linux tutorial for beginners is an absolute guide to Learn Unix/Linux basic fundamentals, Linux command line, UNIX programming and many other topics. You don’t even have to buy a new PC to learn Linux. You can run Linux, right within your existing Windows or Mac OS systems! (Detailed steps are given in these Linux/UNIX tutorials).
…这份 Linux 初学者教程是学习 Unix/Linux 基础原理、Linux 命令行、UNIX 编程及许多其他主题的绝对指南。…

UNIX / Linux Syllabus

Linux Fundamentals

Lesson 1What is Linux? — Introduction to Linux Operating System (OS)
Lesson 2How to Install Linux — How to Download & Install Linux (Ubuntu) in Windows PC
Lesson 3Linux vs Windows — What’s the Difference?
Lesson 4Linux Command Line Tutorial — Manipulate Terminal with CD Commands

Getting Started

Lesson 1Linux/Unix Basic Commands — Learn Basic Linux Commands with Examples & Syntax
Lesson 2File Permissions in Linux/Unix — How to Read/Write & Change?

Advance Stuff!

Lesson 1Linux I/O Redirection — Input Output Redirection in Linux/Unix Examples
Lesson 2Pipe, Grep and Sort Command in Linux/Unix — Learn with Examples
Lesson 3Linux Regular Expression Tutorial — Learn Grep Regex with Examples

Know the OS!

Lesson 1Environment Variables in Linux — List of Environment Variables in Linux/Unix
Lesson 2Linux Networking Commands — SSH, Ping, FTP, Telnet Communication Commands
Lesson 3Telnet Vs SSH — Key Differences
Lesson 4Linux/Unix Process Management — ps, kill, top, df, free, nice Commands
Lesson 5VI Editor Linux Tutorial — VI Editor with Commands in Linux/Unix Tutorial
Lesson 6Unzip Files in Linux — How to Unzip Files in Linux and Ubuntu

Let’s Code!

Lesson 1Shell Scripting Tutorial — How to Create Shell Script in Linux/Unix
Lesson 2Linux/Unix Virtual Terminal — What Is A Virtual Terminal In Linux/Unix?
Lesson 3Linux User Commands Tutorial — Administration & Management
Lesson 4Unix Vs. Linux — What’s the Difference Between Unix and Linux?
Lesson 5Crontab in Linux — Job Scheduling EXAMPLES
Lesson 6Best Linux Certifications — RHCE, LPI, CompTIA, Linux Foundation
Lesson 7Linux Command Cheat Sheet — Basic Linux commands with Example
Lesson 8Best FTP Client Software — 20 Best FTP Client for Windows & Mac
Lesson 9Best SFTP Server — 15+ BEST (FREE & Paid) SFTP Servers for Windows/Linux
Lesson 10Best TFTP server — 7 Best (Really Free) TFTP Server for Windows/Linux
Lesson 11Best Linux Distros — 10 Best Linux Distros
Lesson 12Shell Scripting Interview Q & A — Top 50 Shell Scripting Interview Questions & Answers
Lesson 13TCL TK Tutorial — Tool Command Language
Lesson 14Linux Interview Questions — Top 60 Linux Interview Questions and Answers
Lesson 15Unix Interview Questions — Top 50 Unix Interview Questions and Answers
Lesson 16Linux Books — 15 Best Linux Books for Beginners & Experts
Lesson 17Linux Tutorial PDF — Download Linux Tutorial PDF for Beginners

来自 Unix/Linux 的编程启示录

涅槃 1992
2017.02.08 05:47:45 最后编辑于 :2017.12.05 13:58:43

本文的灵感最初源于 2016 年 11 月,我将工作环境切换到 Mac OS 上,其中一些使用上的“差异”让我对 Unix/Linux 中的设计产生了浓厚的兴趣。在探究过程中,以下经典著作再次让我获益匪浅:

  • C 和指针
  • C 专家编程
  • 深入理解计算机系统 (原书第 3 版)
  • Linux/Unix 设计思想
  • Linux Shell 脚本攻略

前两本书购于 2013 年,我断断续续地读了许久,这一次重读令人豁然开朗,其中许多不解之处在《深入理解计算机系统》一书中得到答案。而后两本则是我在年前有幸读到的。《Linux/Unix 设计思想》虽不谈技术细节,却揭示了 Linux/Unix 隐含的指导思想,而最后一本则是从 Shell 出发,以实践的角度教你如何利用 Shell (Bash) 在 Linux/Unix 平台上构建有效的解决方案,实乃入门进阶必备。

img

从女娲造人说起

相传天地开辟之初,未有人民。女娲抟黄土做人,因事务繁忙,力不暇供,便引绳于泥中,举以为人。故富贵者为黄土人,贫贱者为引縆人。

img

神一样的程序员

“女娲造人” 的故事可谓人人皆知。女娲是神,而程序员是能力上最接近女娲的存在。如果说女娲创造的是真实的世界,那么程序员则是创造数字世界的人。我们所写下的每行代码、所构建的每个程序,都在让这个数字世界变得丰富多彩。然而,尽管程序员拥有近乎神的能力,却也常常受到“NIH 综合征”的困扰。

程序员之殇

NIH 综合征是什么?Not invented here (NIH) is a stance adopted by social, corporate, or institutional cultures that avoid using or buying already existing products, research, standards, or knowledge because of their external origins and costs.

我们经常为 NIH 综合征所困:在求解解决方案时,常常自认为可以做得更好,或者在看到别人的解决方案时会提出各种质疑。这大多是由于我们缺乏对当时问题解决者所面临限制的认识所造成的:可能是迫于时间或预算的限制,也可能是受限于当时物理资源的限制。

NIH 综合征的特点是人们为了证明自己能够提供更加卓越的解决方案而放弃其他开发人员已经完成的工作。这种狂妄自大的行为表明此人并无兴趣去维护他人竭尽全力提供的最佳成果,也不想以此为基础去挑战新的高度。NIH 综合征本质上是动物天性——“嘿,我更好”的体现,就像所有的公猴都会向母猴证明“我更好”一样。

放弃已有工作成果而另起炉灶的做法无形中浪费了大量时间。一些技术人员在入职新公司后,往往有想推倒一切重来的欲望。我曾有一位朋友连续跳槽很多家公司,每次入职之前都信心满满,不久后便黯然离开。这位朋友能力很不错,但每次入职后总是急于通过推倒重来证明自己的能力。

更糟糕的是,新的解决方案往往只是做了一些改进,与之前并无本质区别。现代的应用往往动辄十几万行代码,远超出每个人所能注意的极限,这也会让程序员产生疏漏,从而使得这个问题变得更糟糕。当然,在少数情况下,新的解决方案确实更好,但这只是因为技术人员早已了解做过的工作,从而针对问题可以提出更高的解决方案。站在现在的角度看历史,还看不出对错,除非你对历史一无所知。

为什么 Linux 会成功

Linux 会成功有很多因素,除却当时环境因素外,其成功之处在于开源的世界让每个人都能得到 Linux 源码,从而使得经验可以被借鉴。事实上,在 Linux 出现之前,借鉴他人编写的软件已成为相当普遍的做法,这也是 GNU 宣言中 GPL 所阐释的思想。

来自 Unix/Linux 的编程启示录

现在我们来看看 Unix/Linux 中那些隐藏的编程哲学。需要说明的是,Unix/Linux 中的编程哲学非常通俗易懂,大多是你已知的,更多时候是我们不曾注意到的。无论你现在负责的系统多么复杂,总会有这些原则可以帮助到你。(要说复杂,还有什么比 Unix/Linux 更为复杂的应用呢?)

原则一:小既是美

当提到“小既是美”时,你可能会首先想到一句谚语:“麻雀虽小,五脏俱全。”那就以麻雀为例来说明为什么小即是美。

一般来说,生物无论形体如何,愈小愈稳定。麻雀相对于人而言,出现“脑残鸟”的几率要小得多;单细胞生物相对于多细胞生物产生显著变异体的概率也要小得多。在软件工程中,情况也是如此。Unix 中的程序大多遵循这条准则,小带来的显著优点如下:

  1. 易于编写
  2. 易于理解
  3. 易于维护
  4. 消耗更少的系统资源
  5. 容易与其他工具组合

尽管你可能已经对这些有所了解,但我还是例行公事地强调一下。

每个程序员心中都有编写一个万能软件的想法,渴望像上帝一样创世,能够名垂青史,但这实在是太难了。越是复杂的问题越令人畏缩不前。想想在上学期间,你是更乐于立刻开始做一道题还是一套题呢?不出意外,我们大多都喜欢从一道题开始。

编写小程序同样如此:我们能够尽快动手去做,并且针对某个点找出更合理的解决方案。另外,由于大脑的结构,我们无法同时关注超过四个以上的点,而复杂的程序需要被关注的点却远大于四个,这就意味着我们可能会犯更多的错误。

小程序带来的另一个好处是容易理解。一个 100 行的程序比一个 1000 行的程序要容易理解得多(在复杂度相同的情况下)。

当程序足够小的时候,它就是一个函数。还有什么比函数更灵活地自由组合呢?当然,大多数小程序不能小到只有一个函数,但尽可能减小程序的大小仍然很重要。Unix/Linux 中的命令便是最佳的示例:cp 用来拷贝,rm 用来删除,组合起来就可以实现移动,简直棒极了。

想必,没人会认为麻雀每天摄入的能量会比人多吧?换到程序当中,就是越小的程序消耗的系统资源会更少,大多数情况下如此。

原则二:让每个程序只做好一件事情

程序员也许只想编写一个简单的应用程序,但随着创新精神的占据上风,他会在程序中这里添加一个功能,那里添加一个选项。很快,你就会发现,本来你只想要一个文本编辑器,但他却给你一个 IDE,最终给你的往往不是惊喜,而是大杂烩。这个问题不但在程序员身上体现出来,同样也会出现在产品经理身上:想要一个计算器对吗?我这里有个超级计算机可以给你用。现在,你只能面对这样一个庞然大物了。

在这里插入图片描述

该思想与“小既是美”相辅相成。“专注一件事”的应用最终会产生一个较小的程序,而小程序往往只有单一的功能,单一功能的程序往往也会很小。另外,每个程序只做一件事情也意味着我们可以集中精力去解决当前任务,全心全意做好本职工作。

原则三:建立原型

原型的建立是一个学习的过程:在该过程中可以知道哪些想法可行,哪些不可行。每一个正确设计的背后都有数百个错误的设计方案。通过建立原型,我们可以在早期剔除掉不良的设计方案,以此来降低风险。换句话说,越早建立原型,离你的软件发布时间就越近。

你的软件发布了吗?

从开始接触软件工程起,我们的前辈就告诉我们:“软件永远不会有开发完的时候,记住,是永远!”“怎么会完不成呢,我只要不做了不就行了么?”现在想想,这比让一个沉迷在购物中的女人停下脚步更难(如果钱是无尽的话)。编写软件亦如此,你永远都会想要加入更多的功能。想加入更多功能的可能不是你,或者是你的产品经理,当然,你的老板也会掺一脚。

我一直在向周围的朋友传递这么一种观点:“世界上唯有不变的事物,那就是变。”对于软件工程同样如此。既然变化无可避免,那软件是怎么完成的?尽管我们做事都希望看到最后的结局,但对于软件而言并非如此。可以说,没有做完的软件,只有发布的软件。

我曾犯过类似的错误。2016 年,我在负责一款移动端产品的开发,希望在一个月内上线第一个版本。由于个人疏忽,当我着手原型工作时,离发布时间只有 20 天的时间了。在这期间,我发现原有的一些方案无法奏效,不得不临时更改一些既有的设计。最终导致第一个版本正式发布的时间超出 15 天。我也曾因此被认为是个糟糕的工程师。在团队没有任何移动应用产品开发经验的情况下,及早开始建立原型或许不会导致如此后果。在离开这家公司之后,我仍倍感惭愧。

原则四:舍弃高效率而取可移植性

偏向高效率往往会导致代码不可移植,而选择可移植性往往会让软件的性能不那么尽如人意。

每当有为了追求高效率而放弃移植性的想法时,请在心中默念以下两句话:

  1. 速度欠佳的缺点会被明天的机器克服。
  2. 好程序不会消失,而会被移植到新平台。
关于优化的两点建议

在 Unix 环境中,可移植性的含义通常意味着人们要转而采用 Shell 脚本来编写软件。抛开平台不谈,关于优化,我有以下两点建议:

  • 不要立刻优化:如无必要,无须优化。换句话说,不要想当然地优化,尤其是在用户无感觉的情况下。
  • 关注微优化:影响性能的往往只有几处,在需要优化的时候,只要解决这几处就好,切莫以优化的名义重构全部。

原则五:使用纯文本来存储数据

文本不一定是性能最好的格式,但却是最通用的。另外,文本文件易于阅读和编辑:在任何平台上,我们都可以轻松地阅读文本数据,或使用标准文本编辑器对其进行编辑。

你可能会考虑到使用纯文本文件拖慢了系统的处理速度,并会找出一系列的证据来证明处理字符串的性能更低。我们承认文本文件确实拖累了系统的性能,但是请记住,明天系统的机器性能必将有大幅度的提高。

原则六:利用软件的杠杆效应

给你一个杠杆,在不考虑杠杆质量的前提下,你真的可以撬动地球。一个人的精力只有这么多,如果想要取得非凡的成就,你就必须放大自己对这个世界的影响力,这就需要你找到其中的“杠杆点”,也就是关键点。

君子性非异也,善假于物也

软件中的杠杆效应就是要善于利用他人已有成果,具体点就是学会利用他人写的代码。在早期,我希望每一行代码都是从自己手中出来,并以此为傲,认为这就是所谓的优秀程序员。多年之后,我才明白,成为一个优秀程序员的关键却和手敲每行代码并无必要联系。

善于利用他人的代码会给程序员自身增加砝码。这可能和很多人的认知相违背。查看别人的工作并夸口说自己做得更好,不代表你能力更强;推导现有的方案重来,那只是模仿,不是创造。

想要解决你手中的任务,编写更多软件的最好方法就是善于借用别人的成果。和大多数程序员一样,我曾认为亲自编写代码能带来“就业保障”,并将这种做法视为核心竞争力。但实际工作中却是相反的。在实现功能的前提下,企业往往认为花费时间更少的程序员更具有高效的生产力。你可能对此感到委屈和不解。这里,我想要说的是:认识企业对你的认识和你对自己的认识之间的差异是非常重要的。

如果有可能,请尽量让你的工作自动化。通过加强自动化工作来利用软件的杠杆效应,能产生巨大的生产力,并且能够更充分地利用好时间。如果你是一个 Linux 开发者,Shell 脚本便是你在寻找的杠杆点。

化作春泥更护花

从另外一个角度来说,允许他人使用你的代码来发挥杠杆作用。大部分工程师喜欢私藏自己的源代码,并视为独一无二、举世珍宝,仿佛自己的“核武器”。他们认为公开自己的源代码,自己就会失去地位,会被公司所抛弃。

那些你以为是“核武器”的代码真的就有如此威力吗?要记住:任何一个有着合理思维的正常人都可以编写出像样的代码。更何况,一个有耐心的程序员完全可以将程序反汇编出来,通过逐步分析,最终发现其中的蛛丝马迹。

Linux 的开发人员认为执意保留源码的控制权并无太大必要。现在你发现,尽管你拥有全部的源码,但却仍然不能创造出比 Linux 更成功的操作系统。我想这足可以打消你心中的忧虑了。

重新认识自豪感

现在重新认识所谓的自豪感。很多程序员将写出优秀的代码、使用先进的技术视为自豪感,但我们最终的产出是用来服务用户的。如果用户不能满意,那么我们所谓的自豪感不过是“孤芳自赏”。

原则七:使用 Shell 脚本来提高杠杆效应和可移植性

谈起脚本语言,很多工程师觉得脚本太弱了,只能用来编写简单的应用,无法工程化。并且不少程序员更乐于编写那些看起来宏大的 Java 或者 .NET 应用,甚至有些程序员认为脚本语言算不上一门语言。

现实给了我们一巴掌:我们从来没有想象过 JavaScript 会有如此发展,以 Node 为代表的新型开发平台,让整个 JavaScript 语言变得非常有活力。

那么我们是否也小觑了 Shell 这种简单的脚本语言呢?有很长一段时间,我不能正确地认识 Shell 是什么,甚至觉得“嗨,这东西好像对我没什么用,它能用来干什么”。让我改变想法的恰好是 2015 年的工作经历。

和其他脚本语言(如 Python、JavaScript)一样,Shell 脚本同样由一个或者多个语句组成,通过调用本地程序、解释程序和其他脚本来执行任务。Shell 脚本将每条指令加载到内存执行。大部分情况下,这些指令是由无数的 Unix/Linux 开发者事先编写完成的,我们要做的就是用 Shell 来间接地利用这些高效、安全的代码。

比如在 Shell 中使用 wget 命令来下载文件时,我们实际书写的不过几行语句,背后支撑我们的确有数万行的代码。如果让你用 Java 写一个下载器,会需要多少工程量呢?又需要耗费多少时间?

现在有些程序员会反驳:我用 Python 写起来也很快,代码也不多。那问题来了,Python 的运行环境可不是先天就存在于 Unix/Linux 中的,但大部分 Unix/Linux 却都支持 Shell。

如果编写的脚本程序要运行在不同的系统中或者运行在许多设备中,Shell 无疑具有更好的移植性,不是吗?

如你所想,及时运行

脚本语言有一个先天的优势,那就是它们是解释型的语言,运行前不需要事先编译。先来看看以 C 语言为代表的编译型语言,要构建一个程序的基本流程如下:

思考 -> 编辑代码 -> 编译 -> 测试

而在 Shell 当中,整个过程更短:

思考 -> 编辑 -> 测试

相比 C 语言,Shell 不存在编译过程,这带来的优势就是:无论 Shell 的应用规模多大、多复杂,只要你想,你就可以运行它、观察它,而无需像 C 语言一样等待编译过程结束后再运行。

Shell 真的慢吗?

一些程序员对 Shell 执行效率过于担忧,认为其效率太低,这就导致了他们为了更高的效率企图采用 C 语言来重写脚本。Shell 脚本的执行效率相对较慢,但一旦 C 程序被装载到内存中运行,纯 C 程序与那些从脚本中调用 C 程序相比,并没有太大的性能优势。

另外,由于 Unix/Linux 中大部分的命令做过相关的优化,反而会比由你编写的纯 C 程序更快。这也引出我想说的另外一点:为了追求更高的性能而更换语言这一做法有待商榷。

如果真是为了追求性能,那么改变通过改良实现方法更有效。例如,在有序数列中查找指定数字采用二分查找比传统的遍历查找的时间复杂度更低,而不是将原来实现遍历查找的 Java 代码改成 C 代码实现。

原则八:避免强制性的用户界面

我最早接触计算机系统是 Windows 2000,应该是在上小学期间。尽管我不知道这个大个“计算器”能够做什么,但可以在没人教的情况下琢磨去做,并学会玩编辑文字、利用文本编辑器和共享来相互交流。当然,少不了的还有纸牌和扫雷。

Window 和 Unix/Linux 理念差异

用户界面能够让任何一个小白在不需要专业知识的前提下迈出操作的第一步。Windows 系列产品和 Unix/Linux 系列产品的不同之一在于它们对用户的看法上:

Windows 的设计者认为用户是畏惧和计算机打交道的,因而提供足够的用户界面来消除用户的恐惧心理。而 Unix 的设计理念则不同,它认为一个接触 Unix/Linux 的用户已经具备了基本的计算机素养,并力求更全面地掌握它。从这个角度而言,Unix/Linux 是选择用户的,而 Windows 是服务用户的。

这也是早期 Windows 比 Unix/Linux 更为大众所接受的关键因素之一。但随着 Unix/Linux 的逐渐发展以及大众计算机素养的提升,越来越多的人开始接受 Unix/Linux 产品,并热衷于此。

像搭积木一样编程

对于程序员而言,我们希望编程应该像搭积木一样,通过不同的组合来实现多样的产品。未来的产品也应该是如此:一些程序员负责开发基础的小模块,另外一些程序员则负责将这些小模块对接成客户所需要的产品。

对于 Unix/Linux 开发者而言的确如此,我们可以利用系统中提供的众多非界面性小程序来组合成我们所需要的。但对于提供用户界面的小程序而言,我们却很难做到这点:用户界面渴望与用户沟通,而非另一个程序。而模拟人在用户界面上的沟通并非易事,你需要花费更多的精力放在非核心需求上。

即使我们能够模拟,从操作效率来看也不容乐观。毕竟用户界面相对命令程序而言本身意味着更多的资源消耗。我想没人愿意在服务器上装一个 KDE 吧?

这就是 Windows 下同样拥有众多的小程序,但却很难将其组合成新产品的原因之一。换言之,我们很难利用前人已产生的成果来发挥杠杆作用。

嗨,我们需要再加个按钮

程序员和产品之间总有一个矛盾点,来看看下面这个对话:

PM:“这里加个按钮。”
RD:“又没有人用,不加不行吗?”
PM:“听我的,加上吧!加了按钮之后就会有人点击……”
RD:“好吧……”
PM:“你看这个地方空白好大,能再加一个按钮吗?”
RD:“我……”

好吧,这是个笑话,我并非想挑起程序员和产品之间的战争。如果你在设计/开发一个界面化的产品,你经常会不由自主地为它加上更多的按钮,企图让它提供更丰富的功能。你总觉得有人会需要它。最终导致项目更加复杂,但用户满意度却未见提升。

有这么一件事到现在对我影响甚大。我想把 Kindle 中的笔记导出到印象笔记,这件事情本来很简单,只需要导出指定的文本文件,解析后导入到印象笔记就可以。

来看看当时我想了什么:我应该做一个界面,可以方便自己操作。别人也可能需要一个保存笔记成 HTML 格式的功能,所以我要添加一个转换按钮。当然,保存、导出按钮也不能忘了,等等……要不要编辑功能?……

这非常好笑,不是吗?由于我第一时间想到了图形界面,接下来就不由自主地想在界面上添加更多的功能。更重要的是,我明明是自己使用的,却站在别人的角度上去给自己提了需求。

如果最终呈现出的是图形化的产品,会发生很有意思的事情。来想一下,我希望它能在每天十二点自动完成导出任务。难道我要再写一个程序来模拟点击操作吗?既然这样,为什么不能让两个程序有能够直接交流的能力呢?(感谢 Unix/Linux 中的管道机制)

现在来看到底发生了什么?当我们想提供界面的时候,就假设是人在操作。这个隐形的假设最终让这个程序失去了自由,好比送给孩子一个用胶水粘合积木而成的城堡,而非一盒积木。

原则九:让每个程序都成为过滤器

程序是什么?早期认为 程序 = 算法 + 数据。但从功能的角度来说,程序即过滤器。

先不要着急反驳。你不觉得在你编写的每个程序中,无论是复杂还是简单,都是以某种形式接受数据,并产生一些数据作为输出吗?这些要输出的数据不就是取决于程序中的算法吗?

有一些人认为过滤器就该是过滤掉不符合期望的东西,而非转换。例如存在一个程序用于过滤掉集合中元素值为 0 的元素,这对于大部分人而言是最直观的有关过滤的理解。但要记住,过滤器同样也包含转换的概念。

对于计算器而言,我们输入错误会产生错误提示,而决定产生什么样错误信息的算法就是错误状态输入的过滤器。可以说,算法是人根据需求定义的规则,即算法由人定义。那数据又是怎么来的?一个没有数据输入/输出的程序就像一个不会进食和排泄的人,这种程序没有存在的价值,现实世界也不存在这种人。

原则十:并行思考

计算机界有个经典的笑话:如果一个女人要花十个月生下一个婴儿,是否意味着能让十个女人在一个月内生出一个婴儿呢?笑话中透出的含义非常明显:自然特性导致某些任务必须被串行,任何试图让其并行运行的举动都无法加快它的进程。

在数字计算机的整个历史中,有两个需求不断驱动我们:一是我们想让计算机做的事情更多,另一个是我们想让计算机运行得更快。而并发则是实现这两个需求的有效途径。

对程序设计而言,并行思考意味着我们应该尽可能利用 CPU 的运算性能,这也要求我们要对任务进行细致有效的分解,寻找其串行路径和并行路径。

现代操作系统通过提供进程、线程及 I/O 多路复用作为并行思考的实现手段。这里我们对这三者做个简单的说明:

  • 进程:每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程有独立的虚拟地址空间,想要和其他控制流通信必须依靠显示的进程间通信,即我们所说的 IPC 机制。
  • I/O 多路复用:应用程序在一个进程的上下文中显式地调度他们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符之后,主程序显式地从一个状态转换为另一个状态。因为程序都是以一个单独的进程运行,所以所有的流都共享同一个地址空间。基本的思路就是使用 select 函数要求内核挂起进程,直到一个或多个 I/O 事件发生后,才将控制权返回给应用程序。
  • 线程:线程应该是我们最为熟知的。它本质是运行在一个单一进程上下文中的逻辑流,由内核进行调度。

现代程序设计语言大都提供对这三种开发方式的支持。例如,C、Node、Python 中常用多进程/线程技术,Java 中的多线程及 NIO 技术等。除此之外,协程也是一种不错的技术方案,例如 Lua、Python 中也提供了对协程的支持。关于这几种实现并发编程的技术方案,我将在随后的文章中解析。

最后补充一点,无论机器速度快慢,我们都可以将多个机器串联在一起,从而得到一个运行速度更快的集群。这就是现代服务器技术的核心之一:大凡高性能的服务器应用背后都有集群的身影,而这些集群大都依托于高性能、廉价的 Unix/Linux 平台。

原则十一:各部分之和大于整体

水泥、沙子、石子和水各自的硬度不高,但混合起来却能得到高硬度的混凝土。这个现实展示了一个很普通的道理:对不同特性的物质进行组合往往能产出令人意外的结果。这种不遵循数学上“1 + 1 = 2”的规律,却和化学反应非常类似。

放在软件工程中同样如此:通过组合小程序来构建集成性的应用程序。这就和我在上文中提到的“像搭积木一样编程”一样。深究下来,无论是搭积木还是编程,其中的共性就是组合的思想

从原子到分子,从树木到高楼大厦,从函数到程序,看似不相关的东西经组合产生出意想不到的结果。在某种意义上,组合的思想是我们人类大脑最重要的能力之一。

原则十二:寻找 90% 的解决方案

“金无足赤,人无完人”这句朗朗上口的话放在软件领域却代表一个不争的事实:没有一个软件能百分百地满足用户。

说得更直白点,你的软件在用户看来总缺少点什么。无论你做出什么努力,这也从另一个角度说明“只有已发布的软件,而没有完成的软件”。

中国邮政 vs 顺丰

既然没有完美的软件,那对于软件开发者而言,有一个非常艰难的决定:“我们该向用户提供什么”。这是一个非常有意思的问题,其答案取决于你所开发软件的性质以及面向的用户群体。

说到这,就不得不谈起中国邮政和顺丰速递。在中国的每个地方,你都可以用中国邮政来收发快递,而顺丰却只见于经济发展不错的地区。很多人像我一样曾抱怨过邮政的效率太低,接下来感叹一句要是有顺丰该多好。

现在我们客观地来谈谈同为快递的这两者本质差异:邮政作为一家国企,在政府的要求下,邮政必须服务所有的人,必须提供 100% 的解决方案;而顺丰作为一家独立的商业公司,却可以选择性服务,通过专注于高利润且容易做到的 90%。最终的结果就是我们普遍觉得顺丰具有更高的效率。

这其中的关键在于我们需要故意忽略那些代价昂贵、费时费力或难以解决的问题。从商业的角度来说,这是一种“低投入,高回报”的解决方案。现在我们可以来谈谈软件开发了。

无论你是个人开发者还是商业软件公司负责人,都应该考虑这个问题:“向用户提供什么才最有价值”,然后去解决这其中的 90%。这可能令很多人不适,但现在互联网公司最不应该做的就是企图提供像邮政一样的 100% 的服务。

提供 90% 的方案除了能获得更高的效益之外,还可以帮助聚集你的用户群体。这也是我在 2015 年创业期间最大的感触之一。

原则十三:层次化思考

层次化思想是什么?说起来很抽象,不如直接问自己一个问题:“金字塔是如何建成的?”如果你的回答是一层一层建成的,那么你可以直接略过本章节了。

层次化思考并非新名词。对大部分程序员而言,“分层”是所有解决方案的指导思想,这里的分层便是层次化思考的结果。与层次化思考相关的一种分析方法是 AHP(Analytic Hierarchy Process),即层次分析法(关于 AHP 更多的信息在此不多讲)。它是思考和构造复杂系统的一个基本方法,按照该方法设计出的系统具有明显的层次体系。

现实世界充斥着层次化结构,小到细胞结构,大到宇宙,从小团队到跨国公司,都呈现出层次化结构。对计算机软件而言亦如此。在层次体系中,下层构件为上层构件提供服务支撑,上层和下层之间的关系就像是方法的“调用 - 返回”。采用层次化设计的应用就像金字塔,先有底层构件,然后在之上构建高层构件。相对低层构件而言,高层构件更容易理解。

可以说,一个系统无论最初采用什么样的组织方式,最终都会走向分层体系。

我经常说的一句话是:无分层不架构。通俗点说,就是没有分层的应用是没有架构可言的。分层结构在计算机世界中无处不在,来看几个最典型的例子:

ISO/OSI 七层网络模型

在这里插入图片描述

WEB 应用分层结构

在这里插入图片描述

Unix/Linux 系统分层结构

在这里插入图片描述

Android 系统分层结构

在这里插入图片描述

MVC & MVP

除了上述几个典型示例外,两种典型的开发方式 MVC 和 MVP 也都是典型的分层结构:

在这里插入图片描述

无论是 MVC 还是 MVP,亦或是 MVVM,还是将来可能出现的什么 M*P,只要记住所有的开发方式本质都是层次思考的结果,最终呈现分层体系。这就是所谓的“万变不离其宗”。

总结

也许你会像我当初一样纳闷:这么优秀的操作系统就靠这些看起来无比简单的理念引导?事实确实如此,这有点像我们所说的“大道至简”,复杂的东西简单做,也是我们解决问题的最重要的一步。

关于 Unix/Linux 中的编程哲学,我认为以上十三条已经足够。其中最有启发的应属“小既是美”,这也是我决定以后不写长文的原因。


via:

  • UNIX / Linux Tutorial for Beginners: Learn Online in 7 days
    https://www.guru99.com/unix-linux-tutorial.html

  • 来自 Unix/Linux 的编程启示录 - 简书 涅槃 1992 2017.02.08 05:47:45 最后编辑于 :2017.12.05 13:58:43
    https://www.jianshu.com/p/d0e06af905cb

相关文章:

Unix/Linux | A Programming Guide

注:本文为 “UNIX / Linux 教程” 相关文章合辑。 略作重排,如有内容异常,请看原文。 UNIX / Linux Tutorial for Beginners: Learn Online in 7 days By : Emily Carter UpdatedFebruary 5, 2025 UNIX / Linux Tutorial Summary Linux …...

前端——布局方式

普通流(标准流) 所谓的标准流: 就是标签按照规定好默认方式排列. 1. 块级元素会独占一行,从上向下顺序排列。 常用元素:div、hr、p、h1~h6、ul、ol、dl、form、table 2. 行内元素会按照顺序,从左到右顺序排列&am…...

Multimodal models —— CLIP,LLava,QWen

目录 CLIP CLIP训练 CLIP图像分类 CLIP框架 Text Enocder Image Encoder LLava系列 LLava LLava贡献 LLava模型结构 总结 LLava两阶段训练 LLava 1.5 LLava 1.6 QWen CLIP CLIP是OpenAI 在 2021 年发布的,最初用于匹配图像和文本的预训练神经网络模型…...

Python模块化编程进阶指南:从基础到工程化实践

一、模块化编程核心原理与最佳实践 1.1 模块化设计原则 根据企业级项目实践,模块化开发应遵循以下核心原则: ​​单一职责原则​​:每个模块只承担一个功能域的任务(如用户认证模块独立于日志模块)​​接口隔离原则…...

json-server的用法-基于 RESTful API 的本地 mock 服务

json-server 是一个非常方便的工具,用于快速搭建基于 RESTful API 的本地 mock 服务,特别适合前端开发阶段模拟后端数据接口。 🧩 一、安装 npm install -g json-server🚀 二、快速启动 创建一个 db.json 文件(模拟数…...

LabVIEW与PLC通讯程序S7.Net.dll

下图中展示的是 LabVIEW 环境下通过调用S7.Net.dll 组件与西门子 PLC 进行通讯的程序。LabVIEW 作为一种图形化编程语言,结合S7.Net.dll 的.NET 组件优势,在工业自动化领域中可高效实现与 PLC 的数据交互,快速构建工业监控与控制应用。相较于…...

STM32 __main汇编分析

在STM32的启动流程中,__main是一个由编译器自动生成的C标准库函数,其汇编级调用逻辑可通过启动文件(如startup_stm32fxxx.s)观察到,但具体实现细节被封装在编译器的运行时库中。以下是其核心逻辑解析: 一、…...

使用GpuGeek高效完成LLaMA大模型微调:实践与心得分享

使用GpuGeek高效完成LLaMA大模型微调:实践与心得分享 🌟嗨,我是LucianaiB! 🌍 总有人间一两风,填我十万八千梦。 🚀 路漫漫其修远兮,吾将上下而求索。 随着大模型的发展&#xff0…...

华为IP(6)

VLAN聚合 VLAN聚合产生的技术背景 在一般是三层交换机中,通常采用一个VLAN接口的方式实现广播域之间的互通,这在某些情况下导致了IP地址的浪费 因为一个VLAN对应的子网中,子网号、子网广播地址、子网网关地址不能用作VLAN内的主机IP地址&a…...

1:OpenCV—图像基础

OpenCV教程 头文件 您只需要在程序中包含 opencv2/opencv.hpp 头文件。该头文件将包含应用程序的所有其他必需头文件。因此&#xff0c;您不再需要费心考虑程序应包含哪些头文件。 例如 - #include <opencv2/opencv.hpp>命名空间 所有 OpenCV 类和函数都在 cv 命名空…...

第三部分:内容安全(第十六章:网络型攻击防范技术、第十七章:反病毒、第十八章:入侵检测/防御系统(IDS/IPS))

文章目录 第三部分&#xff1a;内容安全第十六章&#xff1a;网络型攻击防范技术网络攻击介绍流量型攻击 --- Flood攻击单包攻击及防御原理扫描窥探攻击畸形报文攻击Smurf攻击Land攻击Fraggle攻击IP欺骗攻击 流量型攻击防御原理DDoS通用攻击防范技术 ---- 首包丢弃TCP类攻击SYN…...

Void: Cursor 的开源平替

GitHub&#xff1a;https://github.com/voideditor/void 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Void&#xff0c;这款编辑器号称是开源的 Cursor 和 GitHub Copilot 替代品&#xff0c;而且完全免费&#xff01; 在你的代码库…...

100G QSFP28 BIDI光模块一览:100G单纤高速传输方案|易天光通信

目录 前言 一、易天光通信100G QSFP28 BIDI光模块是什么&#xff1f; 二、易天光通信100G QSFP28 BIDI光模块采用的关键技术 三、100G QSFP28 BIDI光模块的优势 四、以“易天光通信100G BIDI 40km ER1光模块”为例 五、总结&#xff1a;高效组网&#xff0c;从“减”开始 关于…...

基于大模型的脑出血智能诊疗与康复技术方案

目录 一、术前阶段1.1 数据采集与预处理系统伪代码实现流程图1.2 特征提取与选择模块伪代码实现流程图1.3 大模型风险评估系统伪代码实现流程图二、术中阶段2.1 智能手术规划系统伪代码实现流程图2.2 麻醉智能监控系统伪代码实现流程图三、术后阶段3.1 并发症预测系统伪代码片段…...

卓力达电铸镍网:精密制造与跨领域应用的创新典范

目录 引言 一、电铸镍网的技术原理与核心特性 二、电铸镍网的跨领域应用 三、南通卓力达电铸镍网的核心优势 四、未来技术展望 引言 电铸镍网作为一种兼具高精度与高性能的金属网状材料&#xff0c;通过电化学沉积工艺实现复杂结构的精密成型&#xff0c;已成为航空航天、电…...

今日积累:若依框架配置QQ邮箱,来发邮件,注册账号使用

QQ邮箱SMTP服务器设置 首先&#xff0c;我们需要了解QQ邮箱的SMTP服务器地址。对于QQ邮箱&#xff0c;SMTP服务器地址通常是smtp.qq.com。这个地址适用于所有使用QQ邮箱发送邮件的客户端。 QQ邮箱SMTP端口设置 QQ邮箱提供了两种加密方式&#xff1a;SSL和STARTTLS。根据您选…...

快速入门机器学习的专有名词

机器学习&#xff08;Machine Learning&#xff09; 机器学习是计算机科学的一个领域&#xff0c;目的在于让计算机能够通过学习数据来做出预测或决策&#xff0c;而无需被明确编程来完成任务。 机器学习的工作模式&#xff1a; 数据&#xff1a;机器学习需要数据来“学习”…...

C#学习教程(附电子书资料)

概述 C#&#xff08;读作"C Sharp"&#xff09;是一种由微软开发的现代编程语言&#xff0c;结合了C的高效性和Java的简洁性&#xff0c;专为.NET框架设计。以下是其核心特性和应用领域的详细介绍电子书资料&#xff1a;https://pan.quark.cn/s/6fe772420f95 一、语…...

Python之三大基本库——Matplotlib

好久没来总结了&#xff0c;今天刚好有时间&#xff0c;我们来继续总结一下python中的matplotlib 一、什么是Matplotlib ‌Matplotlib‌是一个Python的2D绘图库&#xff0c;主要用于将数据绘制成各种图表&#xff0c;如折线图、柱状图、散点图、直方图、饼图等。它以各种硬拷贝…...

Tensorflow 2.X Debug中的Tensor.numpy问题 @tf.function

我在调试YOLOv3模型过程中想查看get_pred函数下面的get_anchors_and_decode函数里grid_shape的数值 #---------------------------------------------------# # 将预测值的每个特征层调成真实值 #---------------------------------------------------# def get_anchors_a…...

element基于表头返回 merge: true 配置列合并

<template><div class"wrap" v-loading"listLoading"><div class"content_wrap mt-10"><div style"text-align: center;"><h3>酿造交酒酒罐统计表&#xff08;{{month}}月{{day}}日&#xff09;</h3…...

sql sql复习

虽然之前学习过sql&#xff0c;但由于重在赶学习进度&#xff0c;没有学扎实&#xff0c;导致自己刷题的时候有的地方还是模模糊糊&#xff0c;现在主要是复习&#xff0c;补一补知识点。 今日靶场&#xff1a; NSSCTF 云曦历年考核题 在做题之前先回顾一下sql注入的原理&…...

MySQL 8.0 OCP 1Z0-908 题目解析(1)

题目001 Choose two. User fwuserlocalhost is registered with the SQL Enterprise Firewall and has been granted privileges for the sakila database. Examine these commands that you executed and the results: mysql> SELECT MODE FROM INFORMATION_SCHEMA.SQL…...

介绍一下什么是 AI、 AGI、 ASI

1. AI&#xff08;人工智能&#xff09;&#xff1a;工具化的“窄域智能”​​ 定义​&#xff1a; AI 是能够执行特定任务的智能系统&#xff0c;依赖大量数据和预设规则&#xff0c;​缺乏自主意识和跨领域通用性。 特点​&#xff1a; ​任务专用​&#xff1a;如图像识…...

利用 Amazon Bedrock Data Automation(BDA)对视频数据进行自动化处理与检索

当前点播视频平台搜索功能主要是基于视频标题的关键字检索。对于点播平台而言&#xff0c;我们希望可以通过优化视频搜索体验满足用户通过模糊描述查找视频的需求&#xff0c;从而提高用户的搜索体验。借助 Amazon Bedrock Data Automation&#xff08;BDA&#xff09;技术&…...

TypeScript装饰器:从入门到精通

TypeScript装饰器&#xff1a;从入门到精通 什么是装饰器&#xff1f; 装饰器&#xff08;Decorator&#xff09;是TypeScript中一个非常酷的特性&#xff0c;它允许我们在不修改原有代码的情况下&#xff0c;给类、方法、属性等添加额外的功能。想象一下装饰器就像给你的代码…...

模拟jenkins+k8s自动化部署

参考 Jenkins+k8s实现自动化部署 - 掘金 手把手教你用 Jenkins + K8S 打造流水线环境 - 简书 安装插件 调整插件升级站点 (提高插件下载速度) 默认地址 https://updates.jenkins.io/update-center.json 新地址 http://mirror.xmission.com/jenkins/updates/update-center.json …...

MySQL——十一、主从复制

主从复制是指将主数据库的DDL和DML操作通过二进制日志传入从库服务器中&#xff0c;然后在从库上对这些日志重新执行&#xff08;重做&#xff09;&#xff0c;从而使得从库和主库的数据保持同步。 优点&#xff1a; 主库出现问题&#xff0c;可以快速切换到从库提供服务实现读…...

Ubuntu操作合集

UFWUncomplicated Firewall 查看状态和规则&#xff1a; 1查看状态sudo ufw status&#xff0c; 2查看详细信息sudo ufw status verbose&#xff0c; 默认策略配置&#xff1a; 1拒绝所有入站sudo ufw default deny incoming 2允许所有出战sudo ufw default allow outgoing …...

【TDengine源码阅读】TAOS_DEF_ERROR_CODE(mod, code)

2025年5月13日&#xff0c;周二清晨 #define TAOS_DEF_ERROR_CODE(mod, code) ((int32_t)((0x80000000 | ((mod)<<16) | (code))))这段代码定义了一个宏 TAOS_DEF_ERROR_CODE(mod, code)&#xff0c;用于生成一个32位有符号整数&#xff08;int32_t&#xff09;形式的错误…...