type
status
date
slug
summary
tags
category
icon
password
他从这次经历中学到的两个教训是清晰文档的重要性,以及通过仔细设计可以在很大程度上避免程序调试。
在《谦虚的程序员》(1972 年)中,Dijkstra 写道:“我们不能忘记,编写程序不是我们(计算科学家)的职责,我们的职责是设计能够显示所需行为的计算类。”
Dijkstra 还反对将软件工程纳入学术计算机科学的范畴。他写道,“正如经济学被称为‘悲惨的科学’一样,软件工程应该被称为‘注定要失败的学科’,因为它的目标是自相矛盾的,所以它甚至无法接近它的目标。”并且“软件工程已接受‘如果你不会编程,如何编程’作为其章程。”
他从小就在母亲的指导下对简单产生了兴趣。他曾经说过,他曾问过母亲,三角学是不是一个困难的话题。她回答说,他必须学习所有的公式,而且,如果他需要超过五行来证明某件事,那么他就走错了路。
Dijkstra 因倡导结构化编程而于 1972 年获得图灵奖,结构化编程是一种利用结构化控制流的编程范式,而不是使用Goto语句非结构化跳转到程序中的不同部分。
一种观点是,一个真正称职的程序员应该具有解谜的思维,并且非常喜欢聪明的技巧;另一种观点是,编程不过是优化计算过程的效率,无论是朝一个方向还是另一打个方向。
多级存储利用了程序访问数据的空间局部性和时间局部性原理。空间局部性意味着程序倾向于访问相邻的数据,而时间局部性意味着程序倾向于多次访问最近访问过的数据。
但我称这为一个次要原因;主要原因是机器变得强大了几个数量级!坦率地说:只要没有机器,编程根本不是问题;当我们有了一些弱小的计算机时,编程变成了一个轻微的问题,而现在我们有了巨型计算机,编程变成了一个同样巨大的问题。从这个意义上说,电子工业并没有解决任何问题,它只创造了问题--它创造了使用其产品的问题。
似乎有三个主要条件必须满足。首先,整个世界必须认识到变革的必要性;其次,经济上的需求必须显够强烈;第三,变革必须在技术上可行。让我按上述顺序讨论这三个条件。
1968年NATO软件工程会议
1968年,北大西洋条约组织(NATO)科技委员会组织了第一次关于软件工程的会议,这场会议在德国的盖尔森基兴举行。此次会议的目的是讨论和寻找解决方案来应对软件危机。会议提出了“软件工程”这一概念,旨在将系统的、工程化的方法应用于软件开发中,以提高效率和质量,从而解决软件开发中遇到的种种问题。
语言最具讽刺意味的说法之一。我们应该从最近的过去中学到的另一个教训是,开发“更丰富”或“更强大”的编程语言是一个错误,因为这些繁琐的怪物,这些奇特的集合,实际上是不可管理的,无论是机械上还是心理上。
计算机已经教会了我们一些教训,而我在这次演讲中选择强调的是以下几点。只要我们充分认识到这项任务的巨大困难,并坚持使用谦逊而优雅的编程语言,尊重人类思维的内在局限,以非常谦逊的程序员身份来对待这项任务,我们就能做得更好。
Dijkstra 出生于荷兰鹿特丹,在莱顿大学学习数学和物理,随后又在莱顿大学学习理论物理。 Adriaan van Wijngaarden为他提供了一份在阿姆斯特丹数学中心担任荷兰第一位计算机程序员的工作,他从 1952 年一直工作到 1962 年。他于 1956 年提出并解决了最短路径问题,并于 1960 年开发了第一个编译器与同事Jaap A. Zonnevald合作开发的编程语言ALGOL 60 。 1962年,他搬到埃因霍温,后来又搬到纽南,在那里他成为埃因霍温工业大学数学系的教授。在 20 世纪 60 年代末,他构建了多道程序设计系统,该系统通过使用基于软件的分页虚拟内存影响了后续系统的设计。 Dijkstra 于 1973 年 8 月加入Burroughs Corporation ,成为该公司唯一的研究员。在 Burroughs 的岁月里,他的研究论文产出最多。他在“EWD”系列中撰写了近 500 份文档,其中大部分是技术报告,供特定团体内部私人流通。
数学和物理 理论物理
最短路径问题
编译器
ALGOL60
多道程序设计系统
Dijkstra 于 1984 年接受了德克萨斯大学奥斯汀分校计算机科学系斯伦贝谢百年纪念主席职位,在德克萨斯州奥斯汀工作,直到 1999 年 11 月退休。他和妻子从奥斯汀回到了他在纽南的老家,在那里他在与癌症长期斗争后于 2002 年 8 月 6 日去世。 [3]
他因对开发结构化编程语言的基本贡献而获得 1972 年图灵奖。在他去世前不久,他因其在程序计算自稳定方面的工作而获得了分布式计算领域的ACM PODC影响力论文奖。为了纪念他,该年度奖项次年更名为迪杰斯特拉奖。
Edsger W. Dijkstra 出生于鹿特丹。他的父亲是一位化学家,曾任荷兰化学会主席;他在一所中学教化学,后来担任校长。他的母亲是一名数学家,但从未有过正式工作。 [4] [5]
20 世纪 50 年代初,电子计算机还是个新鲜事物。 Dijkstra 的职业生涯是偶然的,通过他的导师Johannes Haantjes教授,他认识了阿姆斯特丹数学中心计算系主任Adriaan van Wijngaarden ,Adriaan van Wijngaarden 为 Dijkstra 提供了一份工作; 1952年3月他正式成为荷兰第一位“程序员” 。 [6]
在进行了大约三年的编程之后,我与 A. van Wijngaarden 进行了一次讨论,他当时是我在阿姆斯特丹数学中心的老板,在我有生之年,我将一直感激他的讨论。关键是,我本来应该在莱顿大学同时学习理论物理,而当我发现这两项活动越来越难结合起来时,我必须下定决心,要么停止编程,成为一名真正的、受人尊敬的理论物理学家。物理学家,或者只是以最小的努力正式完成我的物理学研究,并成为......,是的什么?程序员?但这是一个受人尊敬的职业吗?毕竟,编程是什么?可以支持它成为一门在智力上受人尊敬的学科的健全的知识体系在哪里?我清楚地记得我是多么羡慕我的硬件同事,当被问到他们的专业能力时,他们至少可以指出他们对真空管、放大器和其他东西了如指掌,而我觉得,当面对这个问题时,我会空手而立。我满怀疑虑地敲开了范·韦恩加登办公室的门,问他是否可以“和他谈谈”;几个小时后,当我离开他的办公室时,我已经变成了另一个人。因为在耐心地听完我的问题后,他同意直到那一刻为止还没有太多的编程学科,但随后他继续平静地解释说,自动计算机将继续存在,我们才刚刚开始,可以难道我不是被召唤在未来几年让编程成为一门受人尊敬的学科的人之一吗?这是我人生的转折点,我尽快正式完成了物理学的学习。
当 Dijkstra 于 1957 年与 Maria "Ria" C. Debets 结婚时,作为结婚仪式的一部分,他被要求说明自己的职业。他表示自己是一名程序员,这让当局无法接受,因为当时荷兰还没有这样的职业。
1959 年,他以题为“与自动计算机通信”的论文获得了博士学位, [9]专门描述了为荷兰开发的第一台商用计算机Electrologica X1设计的汇编语言。他的论文导师是 Van Wijngaarden。 [10]
从 1952 年到 1962 年,Dijkstra 在阿姆斯特丹的数学中心工作[10] ,在那里他与Bram Jan Loopstra和Carel S. Scholten密切合作,后者被雇用来制造计算机。他们的交互模式是有纪律的:他们首先通过编写编程手册来决定硬件和软件之间的接口。然后,硬件设计师必须忠实于合同中他们的部分,而程序员 Dijkstra 将为不存在的机器编写软件。他从这次经历中学到的两个教训是清晰文档的重要性,以及通过仔细设计可以在很大程度上避免程序调试。 [6] Dijkstra在1956年ARMAC计算机正式落成典礼上演示并解决了最短路径问题。由于缺乏专门讨论自动计算的期刊,他直到1959年才发表结果。
在数学中心,Dijkstra 和他的同事Jaap Zonneveld [ nl ]于 1960 年 8 月开发了第一个用于编程语言ALGOL 60的编译器,比另一个小组生产编译器早了一年多。 [6] ALGOL 60 被认为是结构化编程兴起的一个关键进步。
Dijkstra 于 1973 年 8 月加入Burroughs Corporation (一家当时以生产基于创新硬件架构的计算机而闻名的公司)担任研究员。他的职责包括每年几次访问该公司的一些研究中心并进行自己的研究,他是在巴勒斯最小的研究设施中进行的,即他位于纽南的房子二楼的书房。事实上,迪杰斯特拉是巴勒斯研究所唯一的研究员,他在家工作,偶尔会前往其在美国的分支机构。结果,他将在大学的预约减少到每周一天。那天,星期二,很快就被称为著名的“星期二下午俱乐部”日,在一场研讨会上,他与同事讨论科学文章,研究各个方面:符号、组织、演示、语言、内容等。 1984年他转到德克萨斯大学奥斯汀分校(美国)后,星期二下午俱乐部的一个新“分支”在德克萨斯州奥斯汀出现。 [10]
巴勒斯时期是他研究论文产出最多的时期。他在 EWD 系列中撰写了近 500 份文档(如下所述),其中大部分是技术报告,供特定小组内部私人流通。 [6]
Dijkstra 在奥斯汀一直工作到 1999 年 11 月退休。为了纪念这一时刻并庆祝他四十多年来对计算机科学的开创性贡献,计算机科学系组织了一次研讨会,并于 2000 年 5 月在他 70 岁生日那天举行。 [6]
迪杰斯特拉和妻子从奥斯汀回到了荷兰纽南的老家,在那里他发现自己的生命只剩下几个月了。他说他想在德克萨斯州奥斯汀退休,但想在荷兰去世。 Dijkstra 在与癌症长期斗争后于 2002 年 8 月 6 日去世。 [3] [12] [13] [14]他和他的妻子留下了三个孩子:Marcus、Femke 和计算机科学家 Rutger M. Dijkstra。 [15]
在计算科学界,Dijkstra 是众所周知的“人物”。在他的《编程学科》 (1976)一书的序言中,他说道:“由于没有参考书目,我既不提供解释,也不道歉。”事实上,他的大部分文章和书籍根本没有参考资料。 [10] Dijkstra 选择这种工作方式是为了保持自力更生。 [18]
作为一生中大部分时间的大学教授,迪杰斯特拉不仅将教学视为一项必需的活动,而且将其视为一项严肃的研究工作。 [6]他的教学方法非常规。 [19]他的讲课风格被认为是独特的。授课时,句子之间的长时间停顿常常被归咎于英语不是迪杰斯特拉的母语。然而,停顿也是他快速思考的一种方式,他在讲课时被认为是一个快速而深刻的思考者。他为奥斯汀的学生开设的课程与计算机科学关系不大,但涉及数学证明的呈现。 [10]每个学期开始时,他都会给每个学生拍一张照片,以便记住他们的名字。他从不遵循教科书,可能例外的是他自己的教科书正在准备中。演讲时,他会用粉笔在黑板上写校样,而不是使用头顶上的箔纸。他邀请学生提出想法,然后他进行探索,或者拒绝探索,因为它们违反了他的一些原则。他布置了具有挑战性的家庭作业,并会深入研究学生的解决方案。他用了整整一周的时间进行了口试期末考试。每个学生都在迪杰斯特拉的办公室或家里接受检查,检查持续几个小时。 [6]
迪克斯特拉评估人们工作能力的方式也极具独创性。 1990 年,当弗拉基米尔·利夫希茨 (Vladimir Lifschitz)来到奥斯汀参加工作面试时,迪杰斯特拉 (Dijkstra) 给了他一个难题。利夫希茨解决了这个问题,并从那时起一直在奥斯汀工作。 [10]
几十年来,他在自己的工作中避免使用计算机。即使在他屈服于德克萨斯大学同事的鼓励并购买了一台麦金塔电脑之后,他也只用它来发送电子邮件和浏览万维网。 [20] Dijkstra 从未使用计算机撰写文章。他更喜欢依靠打字机,后来又使用万宝龙钢笔。 [10] Dijkstra 最喜欢的书写工具是万宝龙大班钢笔。
他不使用文字处理程序,认为一个人应该能够写一封信或一篇文章,而无需草稿、重写或任何重要的编辑。他在动笔之前都会先在脑子里想清楚,并曾经提到,当他还是一名物理系学生时,他会一边走在莱顿的街道上,一边在脑海中解决作业问题。 [6]迪杰斯特拉的大部分出版物都是他一人撰写的。他从来没有秘书,所有信件都由他独自处理。 [10]当同事为他的六十岁生日准备一份由施普林格出版社出版的纪念文集时,他不厌其烦地在一封手写信中分别感谢了 61 位贡献者。
在《谦虚的程序员》(1972 年)中,Dijkstra 写道:“我们不能忘记,编写程序不是我们(计算科学家)的职责,我们的职责是设计能够显示所需行为的计算类。”
Dijkstra 还反对将软件工程纳入学术计算机科学的范畴。他写道,“正如经济学被称为‘悲惨的科学’一样,软件工程应该被称为‘注定要失败的学科’,因为它的目标是自相矛盾的,所以它甚至无法接近它的目标。”并且“软件工程已接受‘如果你不会编程,如何编程’作为其章程。” [21]
迪杰斯特拉过着朴素的生活方式,甚至达到了斯巴达式的程度。 [10]他和他的妻子在纽南的房子简单、小而不张扬。他没有电视、视频播放器或移动电话,也不去看电影。 [10]他弹钢琴,在奥斯汀期间喜欢听音乐会。作为一名古典音乐的热心听众,迪科斯特拉最喜欢的作曲家是莫扎特。 [6]
在迪杰斯特拉的整个职业生涯中,他的作品以优雅和简洁为特点。 [10] Dijkstra 是一位多产的作家(尤其是散文家),撰写了 1,300 多篇论文,其中许多是用他精确的手稿手写的。它们是散文和寓言;童话故事和警告;全面的解释和教学借口。大多数是关于数学和计算机科学的;另一些是旅行报告,这些报告更多地揭示了作者的情况,而不是所访问的人和地点的情况。他的习惯是复制每篇论文并将其分发给一小群同事,这些同事将这些论文复制并转发给另一组有限的科学家。 [22]
迪杰斯特拉以其用钢笔仔细撰写手稿的习惯而闻名。这些手稿被称为 EWD,因为 Dijkstra 以他的名字缩写EWD作为前缀对它们进行编号。根据 Dijkstra 本人的说法,EWD 是在他从阿姆斯特丹数学中心搬到埃因霍温理工大学(当时的埃因霍温理工大学)时开始的。去埃因霍温后,迪杰斯特拉经历了一年多的写作瓶颈。他向同事分发了新 EWD 的复印件。许多收件人复印并转发了他们的副本,因此 EWD 传遍了国际计算机科学界。主题是计算机科学和数学,包括旅行报告、信件和演讲。这些短文跨越了40年的时间。 1972 年之后出现的几乎所有 EWD 都是手写的。它们很少超过 15 页并且连续编号。最后一份(第 1318 号)发布于 2002 年 4 月 14 日。在计算机科学领域,它们被称为 EWD 报告,或简称为 EWD。超过 1300 个 EWD 已被扫描,并且越来越多的 EWD 被转录以方便搜索,并且可以在德克萨斯大学 Dijkstra 档案馆在线获取。 [23]
迪杰斯特拉以其机智、雄辩、粗鲁、唐突,而且常常对专业人士很残酷,以及他的言辞方式而闻名,例如他的评论,“机器是否可以思考(……)的问题与机器能否思考的问题一样重要。潜艇可以游泳。” [25]当一位有前途的研究人员询问如何选择研究主题时,他的建议是:“只做你能做的事”。 [6]迪杰斯特拉还因在与同事互动时直言不讳的批评和缺乏社交技巧而闻名。作为一个直言不讳、批判性的远见者,他强烈反对BASIC的教学。 [26]
迪杰斯特拉在许多诙谐的文章中描述了一家他担任董事长的虚构公司。该公司名为 Mathematics, Inc.,他想象这家公司将数学定理的生产商业化,就像软件公司将计算机程序的生产商业化一样。他发明了 Mathematics Inc. 的许多活动和挑战,并将其记录在 EWD 系列的多篇论文中。这家虚构的公司已经提出了黎曼猜想的证明,但后来在向数学家收取版税时遇到了很大的困难,这些数学家已经证明了黎曼猜想的结果。证据本身就是商业秘密。 [27]公司的许多样张都被匆忙地淘汰了,然后公司的大部分精力不得不花在维护上。 [28]一个更成功的努力是毕达哥拉斯定理的标准证明,它取代了 100 多个不兼容的现有证明。 [29] Dijkstra 将 Mathematics Inc. 描述为“有史以来最令人兴奋和最悲惨的企业”。 [27] EWD 443 (1974) 描述他的虚构公司拥有超过 75% 的全球市场份额。 [30] [31]
Dijkstra 因倡导结构化编程而于 1972 年获得图灵奖,结构化编程是一种利用结构化控制流的编程范式,而不是使用Goto语句非结构化跳转到程序中的不同部分。 1968 年,他写给ACM Communications 编辑的信“ Go To 声明被认为是有害的” ,引起了一场重大争论。现代程序员通常遵循结构化编程的范式。 [32]
(因此,大一的时候,老师说尽量不要使用goto语句)
Dijkstra 因倡导结构化编程而于 1972 年获得图灵奖,结构化编程是一种利用结构化控制流的编程范式,而不是使用Goto语句非结构化跳转到程序中的不同部分。
德克萨斯大学奥斯汀分校计算机科学系 (UTCS) 于 2010 年 10 月 12 日主办了首届 Edsger W. Dijkstra 纪念讲座。牛津大学名誉教授兼微软研究院首席研究员Tony Hoare是该活动的演讲者。该系列讲座是在斯伦贝谢为纪念迪杰斯特拉而提供的慷慨资助下得以实现的。
——(1972)。 《卑微的程序员》 。通讯。 ACM 。 15 (10):859-866。 DOI : 10.1145/355604.361591 。
谦卑的程序员
1952年荷兰出现了第一个程序员
编程行业在荷兰的发展还很慢,但是反观当时的中国,什么东西都还百废待兴,甚至第一个五年计划都没有开始。
多级存储(Memory Hierarchy)
多级存储(Memory Hierarchy)是计算机系统中存储器架构的一种设计理念,它通过组织和管理不同速度和容量的存储设备,以优化整体系统性能和成本。多级存储的基本思想是将存储设备按访问速度和成本进行分级,并根据程序的访问模式,将数据存储在合适的层次中。以下是多级存储的一些关键概念:
- 层次结构:多级存储通常包括以下几个层次,从速度快到慢、容量小到大、成本高到低的顺序排列:
- 寄存器(Registers):位于CPU内部,速度最快,容量最小,用于存储临时数据和指令。
- 缓存(Cache):由多个层次组成,通常分为L1、L2、L3等,位于CPU和主内存之间,存储频繁访问的数据。
- 主内存(RAM):速度较快,容量较大,存储正在运行的程序和数据。
- 辅助存储(Secondary Storage):如硬盘(HDD)、固态硬盘(SSD),速度慢,容量大,存储长期数据。
- 远程存储或云存储(Tertiary Storage):如云存储、磁带存储,速度最慢,容量最大,通常用于备份和归档数据。
- 数据局部性原理:多级存储利用了程序访问数据的空间局部性和时间局部性原理。空间局部性意味着程序倾向于访问相邻的数据,而时间局部性意味着程序倾向于多次访问最近访问过的数据。通过将频繁访问的数据保存在高速存储器中,可以提高访问速度。
- 缓存一致性:在多级存储系统中,尤其是多处理器系统中,保持缓存数据的一致性是一个重要的问题。常用的方法有MESI协议、MOESI协议等,用于确保不同缓存中的数据保持一致。
- 数据迁移与管理:多级存储需要有效的数据迁移和管理策略,以确保数据在不同层次间的转移尽可能透明和高效。这涉及到缓存替换算法(如LRU、LFU等)和预取机制等。
多级存储体系结构通过在不同层次间权衡速度和容量,为计算机系统提供了一种有效的方法,以平衡性能和成本。它使得系统在大多数情况下能够快速访问数据,同时也能处理大量数据。
创造了使用其他产品的问题
封闭子程序 封装的概念,调用API
封闭子程序(Closed Subroutine),在计算机科学中,也常被称为封闭过程或封闭例程,是一种程序设计中的概念。它指的是在某个特定程序中定义的一个代码块,可以被该程序的其他部分调用以执行特定任务。这种子程序设计具有封装性,即其内部的实现细节对调用者是隐藏的。以下是封闭子程序的一些关键特性和概念:
- 封装性:封闭子程序的实现细节对外部调用者是不可见的,调用者只需要了解如何调用子程序(如参数和返回值),而不需要了解其内部实现。这种封装性有助于模块化设计和维护代码。
- 作用域限制:封闭子程序通常只能在其定义的程序中使用,其定义的变量和逻辑在该程序之外不可见。这与开放子程序(Open Subroutine)相对,后者可能被多个程序共享。
- 参数传递:封闭子程序通常通过参数传递来与外部环境进行交互。参数可以是输入参数(传递给子程序的数据)和输出参数(子程序执行后返回的数据)。
- 返回值:封闭子程序通常会返回一个或多个值,作为其执行结果。返回值可以用来决定程序的后续操作。
- 局部变量:在封闭子程序中,通常会使用局部变量来存储临时数据,这些变量的生命周期和作用域限制在子程序内部。
- 重用性和可维护性:封闭子程序使得代码更加模块化,可以被多次调用,提高了代码的重用性。同时,由于其封装性,修改子程序内部的实现通常不会影响到调用它的其他部分,从而提高了代码的可维护性。
例子
以下是一个简单的封闭子程序的例子,以Python语言为例:
在这个例子中,
calculate_area
是一个封闭子程序,它接收一个参数radius
,计算圆的面积并返回。这个子程序的实现细节对调用者是隐藏的,调用者只需要知道如何调用它并使用其返回值。封闭子程序是现代编程语言中的一个基本概念,它帮助程序员组织代码、简化复杂性并提高代码的可读性和维护性。
lsp为什么被称为滥用计算机的最聪明方式?
在上传的图片内容中,文本提到 Lisp 被称为“滥用计算机的最聪明方式”。这个说法通常指的是 Lisp 的设计和使用方式极为灵活,能够让程序员以非常直观和高效的方式控制计算机的行为,甚至可以在运行时创建和修改代码。
Lisp 的特性与其被称为“滥用计算机的最聪明方式”的原因:
- 代码即数据(Code as Data):
- Lisp 的一个核心特点是它的程序可以操作和变更其自身的结构,因为 Lisp 程序的代码(例如函数、变量等)可以作为数据结构来处理。这种能力允许编写非常动态的程序,这些程序能够根据需要在运行时构造新的代码或修改自身结构。
- 宏系统(Macro System):
- Lisp 的宏系统允许开发者定义自己的语法和语言结构,使得可以在编译时期生成和转换代码。这意味着程序员可以“编写编写程序的程序”,极大地提高了语言的表达能力和灵活性。
- 动态类型系统:
- Lisp 通常不要求在编码时声明变量类型,它的动态类型系统允许变量在运行时改变类型。这为程序提供了更多灵活性,但同时也要求程序员更加小心,以避免类型错误。
- 交互式开发环境(REPL):
- Lisp 的读取-求值-打印循环(REPL)环境支持边编程边测试的开发模式,程序员可以逐步构建和测试程序的各个部分,实时观察其行为和结果,这对于快速开发和调试是非常有用的。
为何被视为“滥用”:
在一些人看来,Lisp 提供的极端灵活性和能力可能会导致编写难以理解和维护的代码,特别是当宏和代码生成被过度使用时。程序的这种“滥用”可能使得除了原始编写者之外的其他人难以理解程序的真正行为,从而可能降低代码的可维护性。
总之,Lisp 被称为“滥用计算机的最聪明方式”体现了其语言设计的极端强大和灵活性,这既是一种赞誉也是对其可能导致的复杂性的警示。
宏
宏(Macro),在编程语言中,特别是在像 Lisp 这样的语言中,是一种强大的工具,用于在代码的编译或解释之前对代码进行转换和扩展。宏允许程序员定义新的语法或语言构造,从而在编写代码时可以更灵活地表达程序逻辑。以下是关于宏的一些基本概念和特点:
定义和功能
宏是一种在编译时期执行的代码,可以接收输入代码作为参数,生成新的代码作为替换或增补,然后这个新生成的代码会被编译器继续处理。宏的这种能力允许程序员:
- 自定义语法:通过宏,程序员可以引入新的语法元素,使得代码更加符合特定的应用逻辑或领域特性。
- 避免重复代码:宏可以用来生成重复的或模板化的代码,减少代码冗余。
- 条件编译:宏常用于根据编译时的条件(如平台或配置选项)来包含或排除代码块。
类型
- 文本宏:
- 在像 C 或 C++ 中,宏基本上是简单的文本替换工具。预处理器会在编译前将宏展开,替换掉所有的宏调用。
- 示例(C语言):
2.过程宏:
- 在 Lisp 或 Rust 等语言中,宏可以更复杂,它们可以接受表达式作为参数,并执行更复杂的转换。
- 示例(Lisp语言):
在这个 Lisp 宏例子中,
when
宏接受一个条件和一系列表达式,如果条件为真,则执行这些表达式。优点和缺点
优点:
- 强大的抽象能力:宏提供了一种构建高级抽象的方式,使得代码可以更紧密地与业务逻辑或问题域相匹配。
- 性能优化:通过宏进行代码优化,可以在不牺牲代码可读性的前提下,生成高效的机器码。
缺点:
- 调试难度:宏生成的代码可能难以调试,因为宏展开后的代码与源代码可能差异很大。
- 滥用风险:宏如果使用不当,可能会导致代码的维护性和可读性大幅度下降。
宏是一种在某些编程语言中非常有用的功能,尤其是在需要大量代码生成或特定编程范式支持的场景中。但同时,它们需要谨慎使用,以确保代码的清晰和可维护性。
加米施
软件危机的发生
背景与定义
软件危机是在1960年代末到1970年代初期,在计算机科学领域广泛感受到的一系列问题。它主要是由于软件开发的复杂性远远超出了当时可用的管理和技术方法的范围所引起的。这些问题包括但不限于:
- 软件项目延期
- 软件成本超支
- 软件质量低下
- 软件通常难以维护
- 软件经常无法满足用户需求和规格
1968年NATO软件工程会议
1968年,北大西洋条约组织(NATO)科技委员会组织了第一次关于软件工程的会议,这场会议在德国的盖尔森基兴举行。此次会议的目的是讨论和寻找解决方案来应对软件危机。会议提出了“软件工程”这一概念,旨在将系统的、工程化的方法应用于软件开发中,以提高效率和质量,从而解决软件开发中遇到的种种问题。
影响和结果
1968年的软件危机和随后的NATO会议,对软件开发领域产生了深远的影响:
- 软件工程学科的诞生:软件工程作为一个独立的学科和职业领域被正式承认和发展,它强调必须使用工程原则和方法来开发软件。
- 方法学和工具的发展:为了应对软件危机,研究者和工程师开始开发新的软件开发方法论和工具,如结构化编程、面向对象编程、各种设计模式等。
- 教育和培训的重视:大学和教育机构开始设立专门的软件工程课程,以培养具备必要技能的软件工程师。
- 标准和规范的制定:行业内开始制定更多的标准和规范,以指导软件开发实践,确保软件质量和可维护性。
软件危机揭示了计算机软件开发与硬件技术进步之间的矛盾,促进了软件工程方法和技术的快速发展,从而使得软件开发更加科学和系统化。这场危机和对应的响应,标志着现代软件工程实践的起点。
更有效的方式进行编程
软件工程的重点应该在管理,如何规范化开发才是它的重点
理解
这句话有一定的道理,但需要更全面的理解。软件工程确实涉及到对开发过程的管理和规范化,但它的范畴远不止于此。以下是对软件工程各个方面的详细解析:
管理的重要性
软件工程中的管理是确保项目成功的关键因素之一。良好的管理能够保证项目按时、按预算完成,并且满足质量要求。管理活动包括但不限于:
- 项目规划:定义项目目标、预算、时间表和资源分配。
- 风险管理:识别、评估和缓解项目中可能遇到的风险。
- 质量保证:确保软件产品符合预定的质量标准和用户需求。
- 人员管理:组织和指导开发团队,提升团队协作和效率。
规范化开发的角色
规范化的开发流程是软件工程的另一个核心组成部分,旨在通过标准化的方法提高开发效率和软件质量,减少错误和重工。这些方法可能包括:
- 编码标准:为了保证代码质量和可维护性,制定一致的编码准则。
- 开发方法论:采用如敏捷、瀑布、DevOps等开发框架和实践。
- 持续集成和持续部署:自动化测试和部署过程,确保开发的快速迭代和稳定性。
技术和工具
除了管理和规范化,软件工程还涉及到选择合适的技术和工具来支持开发工作,包括:
- 编程语言和框架:根据项目需求选择最合适的技术栈。
- 工具和平台:使用版本控制系统、集成开发环境(IDE)、测试工具和部署工具等。
- 架构设计:设计软件的整体结构,以支持其可扩展性、性能和安全性。
用户和市场需求
软件工程还必须考虑用户和市场的需求,包括:
- 用户体验设计:设计直观、易用的用户界面和交互流程。
- 需求获取和分析:准确地理解并定义用户需求和系统需求。
结论
因此,虽然管理和规范化开发是软件工程的重要组成部分,但软件工程的实践远比这更广泛。它是一个多方面的学科,涉及从项目管理到技术实施,再到用户需求和市场适应性的各个方面。成功的软件工程需要综合考虑这些方面,以创造出高质量、符合需求且可持续发展的软件产品。
Dijkstra 还反对将软件工程纳入学术计算机科学的范畴。他写道,“正如经济学被称为‘悲惨的科学’一样,软件工程应该被称为‘注定要失败的学科’,因为它的目标是自相矛盾的,所以它甚至无法接近它的目标。”并且“软件工程已接受‘如果你不会编程,如何编程’作为其章程。”
反对将软件工程纳入学术计算机科学的范畴
Edsger Dijkstra 是一位具有深远影响的计算机科学家,他对计算机科学的发展,尤其是程序设计方法论和理论方面做出了重要贡献。Dijkstra 对软件工程领域的批评体现了他对软件开发实践与计算机科学理论之间差异的深刻见解。以下是对他这段话的理解和评价:
批评的背景
Dijkstra 的批评源自于他对软件工程作为一门科学学科的质疑。他认为,软件工程的实践往往偏重于应对实际问题的具体技术和方法,而缺乏严格的科学理论支撑。在他看来,软件工程的一些目标——如减少错误、提高效率和可维护性——在实际操作中常常是自相矛盾的,因为完美的理论模型很难适用于复杂多变的实际开发场景。
“注定要失败的学科”
Dijkstra 将软件工程称为“注定要失败的学科”,反映了他对于软件工程作为一个科学领域的根本怀疑。他认为,由于软件工程必须处理不断变化的需求和不确定的技术环境,其科学方法和理论常常无法达到传统物理科学领域中的严格标准。
对编程教育的看法
Dijkstra 所指的“如果你不会编程,如何编程”章程,暗示了软件工程教育的一个潜在问题:即重视工具和方法的教学,而不足够重视基础的计算理论和思维训练。他认为,缺乏深厚的计算基础和理论支撑的编程教育可能导致编程实践和技能的表层化。
现代观点
虽然 Dijkstra 的批评在某种程度上反映了软件工程早期发展的一些问题,但软件工程作为一个学科已经取得了显著的进展。现代软件工程不仅包括技术和工具的应用,还强调了理论的重要性,如算法分析、系统设计原则和模式识别等。同时,教育领域也在不断尝试将计算理论与实际编程技能相结合,以培养既能理解理论又能应对实际问题的软件工程师。
总结
Dijkstra 的观点提供了对软件工程学科批判性的反思,强调了理论基础的重要性和软件工程实践中的困难。尽管如此,软件工程作为一个学科在理论和实践上都有显著的发展,这有助于更好地理解和应对复杂的软件开发挑战。
即某些编程语言如何通过语言设计来强制编程者遵循特定的编程风格或实践,特别是在结构和控制流的处理上。这里提到了早期的编程语言如 ALGOL 60 和 FORTRAN 中的语法设计,和它们如何通过这些设计决策来引导或限制程序员的编程方式。
这里的核心议题是编程语言的设计哲学——特别是设计者如何通过语言的构造影响或制约编程实践。例如,提到 ALGOL 60 引入了
for
循环,而 FORTRAN 使用 DO
循环的设计选择,这些设计都是为了简化循环结构并促使程序员编写更清晰、更有组织的代码。对这种设计哲学的看法:
- 设计影响行为: 编程语言的设计对程序员的编程习惯和风格有重大影响。良好的设计可以促进更好的编程实践,比如提高代码的可读性、可维护性和效率。这是为什么现代编程语言如 Python 和 Java 在设计上注重简洁性和直观性,以降低错误率并提高开发效率。
- 早期语言的限制与创新: 早期的编程语言,如文中所述的 ALGOL 和 FORTRAN,它们在设计上的创新(如引入结构化控制流语句)对后来语言的发展产生了深远影响。这些设计不仅提供了新的技术手段,也推动了编程范式的发展,例如从过程式编程向对象导向编程的转变。
- 灵活性与规范性的平衡: 编程语言需要在灵活性和规范性之间找到平衡。过度的限制可能抑制创新和灵活应对复杂问题的能力,而过度的灵活性可能导致代码风格不统一,难以维护。理想的设计是提供足够的结构来引导良好实践,同时留出足够的空间以适应各种不同的编程需求。
- 语言的演进: 随着软件开发实践的演进和技术的发展,编程语言也在不断演化。例如,许多现代语言支持多范式编程,提供了更丰富的抽象机制和更强大的库支持,这反映了对早期语言经验的吸收和响应。
总结来说,图片中描述的问题揭示了编程语言设计如何通过约束和促进某些编程实践来形成特定的编程文化。这是编程语言设计者在创建新语言或改进现有语言时必须考虑的重要方面。理解这些设计决策的背景和目的可以帮助我们更好地选择和使用适合特定项目需求的编程语言。
计算机已经教会了我们一些教训,而我在这次演讲中选择强调的是以下几点。只要我们充分认识到这项任务的巨大困难,并坚持使用谦逊而优雅的编程语言,尊重人类思维的内在局限,以非常谦逊的程序员身份来对待这项任务,我们就能做得更好。
理论物理构建数学模型和理论模型来解释和预测现实世界
理论物理
理论物理是物理学的一个分支,专注于发展一套数学模型和理论框架来解释和预测自然界的物理现象。理论物理不仅试图解释已知的现象,也尝试预测新的现象,这些预测之后可以通过实验物理学家进行验证。理论物理的主要目标是找到自然界的基本规律,并将这些规律表达为一套相互一致的数学方程。
理论物理的关键领域包括:
- 经典力学:
- 研究宏观物体在力的作用下的运动规律,包括牛顿力学、拉格朗日力学、哈密顿力学等。
- 电动力学:
- 描述电荷、电场和磁场之间相互作用的理论,由麦克斯韦方程组成成。
- 统计物理:
- 分析和描述大量粒子系统的行为,特别是温度、压力、熵等宏观物理量的统计性质。
- 量子力学:
- 描述微观粒子如电子、光子等的行为,量子理论是理解原子、分子以及凝聚态物质性质的基础。
- 相对论:
- 包括狭义相对论和广义相对论。狭义相对论处理高速运动下的时间和空间问题,广义相对论则是一个描述引力的几何理论。
- 场论:
- 研究场的动力学和相互作用,如电磁场、引力场和量子场理论等。
- 宇宙学:
- 研究宇宙的大尺度结构、起源、演化以及最终命运。
理论物理的方法
理论物理学家通常从观察和实验中抽象出数学模型,使用数学语言描述这些模型,并通过解析或数值方法解决方程来预测新的物理效应或解释已观察到的现象。理论物理的一个关键方面是制定理论模型,这些模型必须足够简洁以解释尽可能多的实验数据,同时保持预测新现象的能力。
理论物理的重要性
理论物理的发展对科技进步有着深远的影响。例如,量子力学的发展直接导致了现代电子学的诞生,包括晶体管、半导体器件、激光等。广义相对论的预测如黑洞、引力波等现象,也在近年来通过实验得到了验证。
总体来说,理论物理试图通过数学和逻辑推理来深入理解我们的宇宙,从基本粒子到整个宇宙的行为,都是理论物理研究的对象。这种追求不仅是为了科学知识的积累,也为新技术的开发提供理论基础。
编译器
编译器是一种计算机程序,它的主要功能是将一种编程语言(源语言)写成的代码转换成另一种编程语言(目标语言)。通常,这种转换是从高级编程语言(如 C、Java)到低级机器语言或汇编语言,使得转换后的代码能够被计算机硬件直接执行。编译器是实现软件应用和系统运行的关键工具之一。
编译器的主要组成部分
- 词法分析器(Lexer):
- 词法分析器的任务是读取源代码,将其分解成一个个有意义的符号,称为词法单元(tokens)。例如,变量名、常量、运算符等。
- 语法分析器(Parser):
- 语法分析器接收词法单元,并根据语言的语法规则将它们组织成抽象语法树(AST)。AST是一种树状数据结构,表示源代码的语法结构。
- 语义分析器:
- 语义分析器对AST进行检查,以确保语句的语义上的正确性,比如类型检查、变量声明的合法性等。
- 中间代码生成器:
- 生成一种中间表示(IR)的代码,这种代码不依赖于具体的机器语言,为优化过程和最终的目标代码生成提供了一个更抽象的层次。
- 优化器:
- 优化器对中间代码进行变换,旨在改善代码的执行效率和减少所需的资源,如减少执行时间或内存使用。
- 目标代码生成器:
- 将优化后的中间代码转换为目标机器的机器语言。这一步骤涉及到具体的指令选择、寄存器分配等底层细节。
- 错误处理:
- 在编译过程中的各个阶段,编译器都需要检测并报告错误,包括语法错误、类型错误等,以帮助程序员调试和修正代码。
编译器的工作流程
编译器的工作流程可以概括为以下几个步骤:
- 预处理:处理源代码中的预处理指令,如C语言中的
#include
和#define
。
- 词法分析:将源代码转换成一系列词法单元。
- 语法分析:将词法单元转换成抽象语法树。
- 语义分析:进行类型检查和其他语义检查。
- 中间代码生成:生成中间表示形式的代码。
- 代码优化:优化中间代码,提高运行效率。
- 目标代码生成:生成可执行的机器代码。
- 链接:将生成的机器代码与其他库或模块代码合并,形成最终的可执行程序。
编译器的设计和实现是计算机科学中的一个复杂且精细的领域,涉及广泛的计算机理论和实践知识。通过编译器,高级编程语言写成的程序被转换成机器能直接执行的形式,是现代软件开发不可或缺的一部分。
ALGOL 60(Algorithmic Language 1960)
ALGOL 60(Algorithmic Language 1960)是一种非常重要的程序设计语言,对后来的许多高级编程语言如 Pascal、C、C++ 和 Java 有着深远的影响。它是在1958年ALGOL 58的基础上发展而来的,由国际小组在1960年正式发布,此小组包括了来自欧洲和美国的计算机科学家。ALGOL 60被设计用来表达复杂的算法,并在科学计算领域特别受到欢迎。
设计目的和特点
ALGOL 60的设计目的主要是为了提供一种能够便于交换算法的语言,这使其成为第一个被广泛认为是为科学计算设计的高级编程语言。ALGOL 60引入了许多现代编程语言中常见的关键特性和概念:
- 块结构:ALGOL 60采用了块结构的概念,允许在程序中定义局部变量的作用域。这对后来的许多语言设计有深远的影响,块结构支持了结构化编程的理念。
- 递归:ALGOL 60支持递归函数,这是程序设计中一个强大的特性,允许函数调用自身。
- 形式参数:支持过程的形式参数,使得编写通用的和可重用的代码成为可能。
- 分号作为语句分隔符:在ALGOL 60中,分号用作语句之间的分隔符,这一约定也被很多后来的语言沿用。
- 严格的类型系统:引入了数据类型的概念,尽管不如后来的语言那样丰富和复杂。
影响
ALGOL 60对编程语言的设计产生了深远的影响。它的许多特性和概念被后续的语言借鉴和发展,特别是在结构化编程和数据抽象方面。例如,Pascal语言就受到了ALGOL的强烈影响,而Pascal又影响了C、C++等现代语言的发展。
编程范例
ALGOL 60的一个典型程序可能看起来是这样的:
这段代码定义了三个整数变量
a
、b
和c
,计算了a
和b
的和,并打印结果。结论
尽管ALGOL 60本身在当今的编程实践中已经不再使用,但它引入的许多核心概念和特性继续影响着现代编程语言的设计和实现。它标志着现代编程语言的早期发展,是理解编程语言历史和发展的重要里程碑。
局部变量的作用域
局部变量的作用域是指程序中可以访问该变量的区域。局部变量通常在函数内部或者一个代码块内部声明,并且只能在其定义的那个函数或代码块内部被访问和修改,这限制了局部变量的可见性,从而有助于保护和封装数据,以及减少变量名冲突的可能性。
局部变量的特点:
- 有限的作用域:局部变量只在其定义的作用域内可见。例如,在一个函数内定义的局部变量只能在这个函数内部使用。
- 生命周期:局部变量的生命周期通常与其作用域的生命周期相匹配。也就是说,一旦代码执行离开了局部变量的作用域,该变量占用的内存通常会被回收。
- 内存分配:局部变量通常在栈上分配(尽管具体细节取决于编译器和语言的实现),这意味着它们的分配和回收速度很快。
- 递归调用:在递归函数中,每次函数调用时局部变量都会重新在栈上创建,这使得每个函数调用都有其自己的变量副本,互不干扰。
作用域的例子
在不同的编程语言中,局部变量的作用域规则可能略有不同,但基本概念是类似的。以下是一个简单的 C 语言例子,展示局部变量作用域的概念:
在这个例子中,
localVariable
在 function()
函数中定义,因此只能在这个函数内访问。尝试在 main()
函数中访问 localVariable
将会导致编译错误,因为它超出了其作用域。总结
局部变量的作用域是编程中一个非常重要的概念,它有助于减少不同部分的程序之间的相互影响,提高程序的可读性和可维护性,并避免全局变量可能引起的问题。理解和正确使用作用域是高效程序设计的关键部分。
多道程序设计系统重点关注的是调度。
多道程序设计系统
多道程序设计系统(Multiprogramming system)是一种计算机操作系统的设计,能够让多个程序同时在单个处理器上运行。这种设计最大化了计算机系统资源的利用率,特别是处理器资源,因为它可以在一个程序等待某个事件(如输入输出操作)完成时,切换到另一个程序执行,从而保持处理器的持续工作。
多道程序设计系统的关键特点
- 并发性:
- 多道程序设计允许多个程序并发运行。尽管在单处理器系统中这些程序并不是真正同时执行,但操作系统通过任务调度策略(如时间片轮转或优先级调度)交替执行每个程序的指令,给用户一种同时运行的错觉。
- 资源共享:
- 在多道程序设计系统中,系统资源(如CPU、内存、I/O设备等)被多个程序共享。操作系统负责管理这些资源,确保每个程序都能公平且有效地访问所需资源。
- 提高吞吐量:
- 通过减少处理器空闲时间,多道程序设计可以提高系统的吞吐量。这意味着系统可以在给定的时间内完成更多的工作。
- 程序间隔离:
- 虽然多个程序可能同时在内存中,但操作系统需要确保它们之间的隔离,防止一个程序的错误影响到其他程序。这通常通过内存保护和地址空间隔离来实现。
工作原理
操作系统利用任务调度算法来管理多个并发运行的程序。当一个程序需要等待(例如,等待I/O操作完成)时,操作系统挂起该程序,并将CPU控制权交给另一个就绪的程序。这种快速切换增加了CPU的利用率,减少了空闲时间。
调度算法
- 先来先服务(FCFS):按照请求的顺序处理程序。
- 短作业优先(SJF):优先处理预计运行时间最短的程序。
- 轮转调度(Round Robin):每个程序分配固定时间片,轮流执行。
- 优先级调度:根据程序的优先级来分配CPU时间。
- 多级队列:根据进程类型将进程分入不同的队列,每个队列有自己的调度算法。
多道程序设计的挑战
- 资源争用:当多个程序试图同时访问同一资源时,可能会发生冲突。
- 死锁:多个程序相互等待对方持有的资源,导致所有程序都无法进展。
- 安全性和隔离:确保一个程序的行为不会影响到另一个程序是操作系统的重要职责。
结论
多道程序设计系统通过提高资源利用率和系统吞吐量,优化了计算机系统的性能。这种系统设计是现代操作系统的核心部分,对于管理复杂的计算任务和提供多用户、多任务的环境至关重要。虽然它带来了许多挑战,如资源管理和程序隔离,但现代操作系统通过精心设计的调度策略和安全措施,有效地解决了这些问题。
- Author:NotionNext
- URL:https://tangly1024.com/article/Edsger%20W.%20Dijkstra%C2%A0%E5%9F%83%E5%85%B9%E6%A0%BC%C2%B7W%C2%B7%E8%BF%AA%E6%9D%B0%E6%96%AF%E7%89%B9%E6%8B%89
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts