当前位置: 首页 > 科技观察

如何快速熟悉一门语言

时间:2023-03-17 15:39:54 科技观察

首先,请原谅我把这个标题弄得有点大,我只是希望你能从我的经历中得到启发。看到很多没有编程背景的人也收藏了这篇文章,太学术的地方我就评论一下。编程一直是我的爱好,我最喜欢的部分与图形有关,但在过去的几年里,我一直在学习电子学。我最初是通过数学软件Mathematica开始编程的,它本身也是一种强大的函数式编程语言,所以我学习了Haskell/Scheme/Prolog等FP语言。后来,我上了一门分布式系统的课程。为了设计分布式系统,我学习了Erlang。因为也是函数式编程,语法是从Prolog借来的,所以用了很久。FP是指函数式编程,是一种基于函数的语言,对应命令式语言,一种指令式语言。指令语言的程序一条一条地执行指令,每条指令都会影响某个存储单元或设备中的数据。函数式语言比较抽象,用操作(函数)本身代替被操作的对象,函数本身可以用其他函数来描述,是一个非常自洽的系统。Haskell和Scheme都是经典的FP语言。本科和研究生后半段,我学了三年FPGA,所以一直在用Verilog和VHDL。它们是描述电路逻辑的语言,也就是说这些代码最终会对应到一个芯片的电路。但是与Erlang有很多相似之处,可能是因为它们都描述了并发系统。所以当时我有一个概念,就是语言受限于它所描述的系统。FPGA全称为现场可编程门阵列(FieldProgrammableGateArray)。我们都知道集成电路的信号是0和1,也就是高低点,而这些0和1可以控制其他电路的通断。这是数字电路的基本原理。我们知道内存中也存储着0和1,于是一些非常有才华的人想到了是不是可以用记忆棒作为开关来控制大量电路的通断呢?这个东西后来实现了,一个叫RossFreeman的人终于实现了商用FPGA,创建了Xilinx,建立了一个很大的产业。(不过RossFreeman在实现FPGA没多久就死于癌症,没看到他开创的大产业,这是题外话。)简单来说,FPGA相当于一个结构可以不断变化的电路。就像人类的神经网络。目前FPGA的使用主要集中在金融领域的高频交易,但是谷歌建立了一个FPGA农场来进行深度学习,分析所有存储在谷歌数据中心的数据(以及Youtube视频),在不同的数据找到它们之间隐藏的联系。如果有一天谷歌搜索能够完全理解自然语言,那一定是FPGA的功劳。研究生后半段和博士前两年,我在做无线传感器网络,无线传感器节点使用了一个神奇的操作系统,叫做Contiki。本系统的特点是使用了protothread,protothread是介于进程和线程之间的概念。调度器切换进程时,只记住当前指令指针,不保存上下文,所以所有内容都必须保存在全局变量中。.这样做的原因是protothread的实现非常简单,无线传感器使用的处理器内存只有2K。无线传感器网络基本上就是我们常说的物联网。每个节点的主要部件是一个小型无线收发芯片和一个小型处理器。由于功耗的限制,这些芯片的性能不可能太高,所以能够在这些芯片上设计出操作系统(或者说多任务处理),真的是巧手才能办到的事情。(当然,如果现在就拿出一个处理器,速度比当年开发UNIX的PDP-11快多了。)Ph./g/n的最后一年)可以提高。但回国后,我不再做硬件,又回到了我最喜欢的图形上。但图形和图像本身是两个截然不同的领域。一般来说,图形(计算机图形学)是指如何显示图像,而图像(??计算机视觉)是指如何识别和处理图像。的字段有交集。我目前在做的两个创业项目是WebGL和二维码识别相关的。这几年做了很多项目,跨度很大。真心觉得知识是无止境的,学得快不如知道得多,最重要的是可以快速找到切入点,快速建立自信。0.为什么需要快速熟悉一门语言/框架?你在网上看到很多人在争论什么语言,什么框架。在此之前,您也听说过中国人是否应该学习英语。语言自始至终都有两个功能。首先是基于实用主义的功能,即与人沟通。每掌握一门新语言,就可以理解使用这种语言的人或物,并进一步驾驭它。会VHDL就可以控制FPGA,会CUDA或OpenCL就可以控制GPU,会kext脚本就可以控制Apple设备,会用英文搜索就可以积累知识计算机比你这个年龄和资格的程序员快得多。第二个功能是基于情感的功能,即使用相同语言的人寻求彼此的认同。当你在国外漂泊多年遇到老乡,或者当你突然回到家乡,发现你能听懂每个人的讲话,甚至包括一些其他语言难以表达的微妙事物或情况时,都会有很大的不同。.程序员很容易在自己使用的语言中找到归属感,通过自己熟悉的语言建立自信心。这会导致骄傲并阻碍进一步学习的道路。语言本身没有好坏之分,一门新语言的诞生总是和它所处的环境有关。如果语言与使用环境无关,即使设计再优雅也不会流行,比如Haskell和Lisp还有方言,反之,比如JavaScript。你想学习一种语言或框架来做一些事情并与使用该语言的人一起工作,所以不要在任何时候对语言或框架发表评论。毕竟这一切都是人创造的,人总是有局限性的。最终目的是控制机器和人交流,而不是自我放纵。1.搭建调试平台在阅读任何书籍之前,首先要阅读文档,在您的机器上搭建调试环境。不管你对这门语言的历史了解得多么透彻,你对这门语言的使用场景了解得多么透彻,即使把这门语言的所有关键字API都背下来也没用。这就像你认为背单词有助于学好英语一样可笑。成功或成熟掌握技能的量化指标很少。如果你非要找一个指标来衡量你离成功或熟练程度有多近,那么最接近的就是你在实践中失败了多少次。2.研究最基本的数据结构几乎所有语言中最基本的数据结构都是Array/List等有标记的时序结构,我们称之为“表”。树/图/字典/矩阵都可以看作是表的扩展。数据库中有大量对字典的增删改查操作,可以让你把不同的东西堆到表里,结构也可以很多样化。但是在图形图像中,有大量的矩阵运算,运算的对象都是非常整齐的数据。写代码的时候,有一个通过实践总结出来的原则,教科书上很少出现,就是代码块之间(代码块是我临时想到的一个词,因为不同范式中的语言单元不同,在Java类中在Python中,对象在Python中,在JS中是原型,在Erlang中是过程等)传递的信息应该是尽可能简单和通用的数据结构,最好不是非常复杂的对象。也就是说,一个码块接收到这样的信息,经过一些运算,就变成了结构复杂、容量很大的信息。那么这个代码块就应该把这些信息尽可能的简化成一个简单通用的数据结构,才算一件事情完成了。如果这个代码块返回海量数据,另一个代码块接收海量数据,那么这个代码块的功能划分就有问题。这就是为什么UNIX选择文本文件作为基本信息组织单位,允许所有的文件都作为文本文件处理,并且明确提出一个程序应该能够输出文本,所以可以看到UNIX里面的程序会输出stderr,这样就可以通过dmesg查看他们的足迹。由于它基于文本文件,因此UNIX非常重视正则表达式(grep、sed、awk、perl等)也就不足为奇了。这些小部件统称为coreutils。只有掌握了这些小部件,你才能了解*x系统(当然包括OSX)的强大功能。现在几乎所有基于表的语言都开始支持map/reduce/filter等操作,自然而然地引入了lambda函数,正是因为它们大大扩展了表结构的表达能力。在JavaScript中,Array是基本的数据结构,但兼容JSON的Object也是。Array和Object可以不区分地替换,但是在JS引擎中,Array和Object的表达是完全不同的,Array通常会被优化。.如果Array的索引不是从0开始连续递增的整数(比如中间有个元素是undefined),那么存储的时候会退化成Object,查找也应该是以Object匹配key的方式执行,会慢很多。在OpenCV中,由于大部分操作都与图像相关,cv::Mat成为基本数据结构,矩阵的各种操作,包括转置、求逆、合并与拆分、SVD等。OpenCV对这个基本数据结构做了很多优化最小化运行时的I/O开销。例如,现在有对Intel处理器的TBB支持。TBB明确表达了程序的并发性。当然,这部分机制是OpenCV封装的。例如,当进行RANSAC操作(拟合一堆点一条直线或一个椭圆)时需要在一个大的点集中进行搜索,不断地求解SVD方程来找到模型的系数。使用TBB,SVD操作可以并发执行,大大提高了性能。所以你首先要做的就是熟悉Mat相关的各种操作。GNURadio是一个软件无线电框架。它需要一个无线收发器直接上下转换。CPU通过程序对代码进行编解码。这些东西以前都是硬件电路做的,现在都是CPU指令。变得非常敏感。GNURadio中有一个类似TBB的机制,将操作改为不同的模块,如FFT和IFFT、功率谱密度等,这些模块之间的接口不仅定义了数据类型,还包括最大和最小允许写入数据速率。不同领域的语言差异很大,语言背后的核心概念可能差异更大。在3D图形领域,矩阵运算是主要方法。在某些情况下,矩阵并不是一种很方便的表达方式,于是就有了欧拉角和四元数,这些符号更简洁,但也更难理解。二维图像领域有一些令人惊叹的算法,比如寻找直线和椭圆的Hough,拟合平面的RANSAC,寻找图像特征的SIFT/FAST,这些在无线通信领域都是不同的。但是不管是哪个领域,总有一套最基本的与领域外的人交流的方式,就是基本的数据结构。3、调试之前提到从基础数据结构入手,因为基础数据结构的运行结果最容易预测。当代码开始变得复杂时,编译器或运行环境可能无法准确地告诉你错误在哪里。有的时候不报错,有的时候不报对错(这样比较容易误导)。编译器或运行时反馈是了解计算机的最佳信息,但由于各种原因可能并不全面。仅仅依靠这些信息会浪费你很多时间,所以你需要想办法让你的代码为你提供更多的信息。在写C代码的时代,我会用到很多printf来帮助我,主要有以下几个功能:打印运行结果在if-else的控制流语句中打印代码流中的fork循环被终止出现bug的三个原因:你对你要做什么了解不够你对你使用的语言的语法特征了解不够你对函数了解不够/libraries/frameworksyouuse所以出现bug后,你首先需要确定你的bug很可能来自上面的哪些问题。当然,很有可能包括这些类型。在这种情况下,错误可能很难找到。让我们先考虑第二个。如果你对语法特征了解不够,请回到基础数据结构层次,做各种简单的例子,解决那个层次的所有语法问题。如果是第三种,那你需要仔细阅读文档和源码。如果你对自己所做的事情了解得不够多,那么这是一件非常微妙和有趣的事情。我告诉你,人的编程能力最终取决于他掌握母语的能力。如果一个人不能向另一个人解释如何做一件事,那么他自然也不能向计算机描述一件事。所以,对于走上程序设计道路的理科生来说,不管他们的数学思维多么突出,当年掉下来的语文课,在以后都会成为短板。相反,如果你观察一下美国各种技术会议的演讲,或者长期为开源项目做贡献的程序员,他们的口才和写作能力都不错。那么如何找到错误呢?当代码得到错误的结果,或者不能正常运行,或者没有通过编译时,就是有什么地方不符合你的预期,导致它出错。您可以从最后的预期结果开始,或沿着最后的错误倒退。当然,最好的是你可以提供每个关键步骤的详细信息,以便以后修改。今天大多数单元测试框架都鼓励甚至要求人们这样做。这不是一个很高端很酷的技术,但是充分考虑到了人类思维的各种缺陷。