详情联系:朱老师 18170060794 微信同号
编程主要有三类问题:
算:根据输入的数据,经过一系列的计算,得到结果。例如:计算一元二次方程的根、计算一些数的平均值。
找:根据输入的数据,列举出所有可能的情况,并找出某一种情况。例如:找出大值、找出短路径。
实现功能:根据输入的数据,完成某项既定的任务。例如:实现“撤销”和“重做”。dunsijiaoyu zz
1. 为什么很多人都说程序员是吃青春饭的?
我想这基于以下几点事实。 中国 IT 行业起步于九十年代,批程序员到现在可能也就四十多岁,并且很多已经转岗了,这导致了目前公司里 40 几岁的程序员。
国内互联网公司兴起的 996 模式,导致了程序员这种脑力劳动者,变相演化成体力劳动者,拼在前面的,熬的晚的,往往是年轻人。你年龄大,琐事多,加不了班?那你 Out 了。 有种不行是别人觉得你不行。
公司鉴于用人成本,在招聘时对年龄的限制,无形中向大众制造出一种偏见。 大龄程序员可能需要为之支付更多与价值不匹配的薪水,而那些身强力壮,能够加班,又价格低廉的年轻程序员更得某些公司垂青。
做程序员没有做领导、走管理路线钱多。 所以很多程序员在三十几岁的时候转向了管理岗位,要么项目经理,要么 Tech Lead, 要么产品经理,这是晋升成功的。晋升不成功的可能就彻底转行或者自己创业去了。 还有少数技术特别牛X的提了级,做了专家、科学家、CTO。 无论是晋升还是提级,这些程序员的薪水都会上一个档次,或者好几个档次。 所以,到了 30岁、40岁,很多有能耐的,要么升职不需要再写代码了,要么出去单干了。 剩下的大龄一线程序员,可想而知,自然会被人非议,被人认为不行,哪怕你就是喜欢写代码,就是不想当领导,这无疑导致大龄一线程序员在职场中很是尴尬和被动。
2. 编程能力是可以随着年龄积累的
这是北卡罗莱纳州立大学计算机科学系的两个人统计出的一组数据。
程序员的编程能力随年龄的分布图。
程序员是吃青春饭吗?多少岁面临着转业?
可见,程序员的编程能力在从25岁左右开始上升,一直到50岁后才会开始下降。
也就是说,程序员的技术能力是可以随着时间积累的,这一点上,跟其他技术职业并没有什么不同。
曾经我有同事去法国出差,回来告诉我,那边还有白胡子老爷爷程序员,我想肯定级别很高吧,就问他什么级别?同事说,就是普通一线程序员。OMG,我还真是长见识了。国内工作多年,我见过的大的程序员也就 40 多岁。国外那些年过花甲,依然奋斗在编程一线的程序员,战斗力肯定是毋庸置疑的。
做单片机起家的周立功,大家应该都知道吧,据说他老人家现在已经退居二线了,但是还是时不时的写写代码。
所以,年龄大就不能编程了,这个观点是错误的,年龄大不仅可以编程,而且经验还会越来越丰富,技术水平会越来越高。
3. 大龄程序员的出路在哪里?
尽管程序员的技术能力是可以随着时间积累的,国外也有很多大神级大龄程序员,但是我们却无法效仿。
因为中国和美国等西方的国情完全不同。
之前我还听说了有美国那边的同事拒绝提级升职的事情,或许他们就是单纯的热爱编程,或许是不想承担更多的责任和压力。这种事情我想很少或者不可能在中国发生,大家都在挤破脑袋地往上冲冲冲,因为升职就意味着钱和地位。
在美国,大家很少会相互攀比,很少会拿金钱来定义一个人成功与否,人们的收入差距也很小。你级别高, 你有钱,who care?
在这种平等自由的氛围中,程序员们不必那么在意钱与别人的眼光,可以持续地在技术领域深耕,这也提供给了大龄程序员成长为大神的沃土。
而在中国,为了“钱”途我们不得不各自重新做出选择。
上面很多是主管因素,我们在说说更多客观因素。
编程语言有几种?太多了。
众多选择,举止不定。
自20世纪60年代以来,上公布的程序设计语言已有上千种之多。上....千.....种......你要怎样在这上千种语言中找到一种适合自己的原因,很难喽?这倒是不需要担心,你可以在全部语言中选择前十的语言中来选择一种适合你的语言。2016年一月份前十的语言有Java、c、c++、c#、python、php、visual ***、javaScript、assmbly language、Ruby。从排行可以看出来,在网页方面用的多的THML语言都没能挤进前十,连前二十都没有进入。而且在列出的语言当中,你少得学两门语言,而且为了你更好的发展c语言是必学的。在学好c语言后你得从中挑出一门语言,为你的主修语言。而且要想掌握好这门语言,你少得花上两年的时间来专研它。但是一旦你在做选择之后,发现你对计算机语言不感兴趣或者失去兴趣,那么你还得重新选择一门适合你的、你感兴趣的语言,之前的时间也算是白费了。
根据冯·诺依曼思想,计算机采用二进制作为数制基础,必须包含:运算器、控制器、存储设备,以及输入输出设备,如下图所示。
程序设计的5个底层逻辑,决定你能走多快
我们先来分析 CPU 的工作原理,现代 CPU 芯片中大都集成了,控制单元,运算单元,存储单元。控制单元是 CPU 的控制中心, CPU 需要通过它才知道下一步做什么,也就是执行什么指令,控制单元又包含:指令寄存器(IR ),指令译码器( ID )和操作控制器( OC )。
当程序被加载进内存后,指令就在内存中了,这个时候说的内存是独立于 CPU 外的主存设备,也就是 PC 机中的内存条,指令指针寄存器IP 指向内存中下一条待执行指令的地址,控制单元根据 IP寄存器的指向,将主存中的指令装载到指令寄存器。
这个指令寄存器也是一个存储设备,不过他集成在 CPU 内部,指令从主存到达 CPU 后只是一串 010101 的二进制串,还需要通过译码器解码,分析出操作码是什么,操作数在哪,之后就是具体的运算单元进行算术运算(加减乘除),逻辑运算(比较,位移)。而 CPU 指令执行过程大致为:取址(去主存获取指令放到寄存器),译码(从主存获取操作数放入高速缓存 L1 ),执行(运算)。
程序设计的5个底层逻辑,决定你能走多快
这里解释下上图中 CPU 内部集成的存储单元 SRAM ,正好和主存中的 DRAM 对应, RAM 是随机访问内存,就是给一个地址就能访问到数据,而磁盘这种存储媒介必须顺序访问,而 RAM 又分为动态和静态两种,静态 RAM 由于集成度较低,一般容量小,速度快,而动态 RAM 集成度较高,主要通过给电容充电和放电实现,速度没有静态 RAM 快,所以一般将动态 RAM 做为主存,而静态 RAM 作为 CPU 和主存之间的高速缓存 (cache),用来屏蔽 CPU 和主存速度上的差异,也就是我们经常看到的 L1 , L2 缓存。每一级别缓存速度变低,容量变大。
下图展示了存储器的层次化架构,以及 CPU 访问主存的过程,这里有两个知识点,一个是多级缓存之间为保证数据的一致性,而推出的缓存一致性协议,具体可以参考这篇文章,另外一个知识点是, cache 和主存的映射,首先要明确的是 cah 缓存的单位是缓存行,对应主存中的一个内存块,并不是一个变量,这个主要是因为 CPU 访问的空间局限性:被访问的某个存储单元,在一个较短时间内,很有可能再次被访问到,以及空间局限性:被访问的某个存储单元,在较短时间内,他的相邻存储单元也会被访问到。
而映射方式有很多种,类似于 cache 行号 = 主存块号 mod cache总行数 ,这样每次获取到一个主存地址,根据这个地址计算出在主存中的块号就可以计算出在 cache 中的行号。
程序设计的5个底层逻辑,决定你能走多快
下面我们接着聊 CPU 的指令执行。取址、译码、执行,这是一个指令的执行过程,所有指令都会严格按照这个顺序执行。但是多个指令之间其实是可以并行的,对于单核 CPU 来说,同一时刻只能有一条指令能够占有执行单元运行。这里说的执行是 CPU 指令处理 (取指,译码,执行) 三步骤中的第三步,也就是运算单元的计算任务。
所以为了提升 CPU 的指令处理速度,所以需要保证运算单元在执行前的准备工作都完成,这样运算单元就可以一直处于运算中,而刚刚的串行流程中,取指,解码的时候运算单元是空闲的,而且取指和解码如果没有命中高速缓存还需要从主存取,而主存的速度和 CPU 不在一个级别上,所以指令流水线 可以大大提高 CPU 的处理速度,下图是一个流水线的示例图,而现在的奔腾 CPU 都是32级流水线,具体做法就是将上面三个流程拆分的更细。
程序设计的5个底层逻辑,决定你能走多快
除了指令流水线, CPU 还有分支预测,乱序执行等优化速度的手段。好了,我们回到正题,一行 Java 代码是怎么执行的?
一行代码能够执行,必须要有可以执行的上下文环境,包括:指令寄存器、数据寄存器、栈空间等内存资源,然后这行代码必须作为一个执行流能够作系统的任务调度器识别,并给他分配 CPU 资源,当然这行代码所代表的指令必须是 CPU 可以解码识别的,所以一行 Java 代码必须被解释成对应的 CPU 指令才能执行。下面我们看下System.out.println("Hello world")这行代码的转译过程。
Java 是一门高级语言,这类语言不能直接运行在硬件上,必须运行在能够识别 Java 语言特性的虚拟机上,而 Java 代码必须通过 Java 编译器将其转换成虚拟机所能识别的指令序列,也称为 Java 字节码,之所以称为字节码是因为 Java 字节码的操作指令(OpCode)被固定为一个字节,以下为 System.out.println("Hello world") 编译后的字节码:
0x00: b2 00 02 getstatic Java .lang.System.out
0x03: 12 03 ldc "Hello, World!"
0x05: b6 00 04 invokevirtual Java .io.PrintStream.println
0x08: b1 return
左列是偏移;中间列是给虚拟机读的字节码;右列是高级语言的代码,下面是通过汇编语言转换成的机器指令,中间是机器码,第三列为对应的机器指令,后一列是对应的汇编代码:
0x00: 55 push rbp
0x01: 48 89 e5 mov rbp,rsp
0x04: 48 83 ec 10 sub rsp,0x10
0x08: 48 8d 3d 3b 00 00 00 lea rdi,[rip+0x3b]
; 加载 "Hello, World!\n"
0x0f: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
0x16: b0 00 mov al,0x0
0x18: e8 0d 00 00 00 call 0x12
; 调用 printf 方法
0x1d: 31 c9 xor ecx,ecx
0x1f: 89 45 f8 mov DWORD PTR [rbp-0x8],eax
0x22: 89 c8 mov eax,ecx
0x24: 48 83 c4 10 add rsp,0x10
0x28: 5d pop rbp
0x29: c3 ret
JVM 通过类加载器加载 class 文件里的字节码后,会通过解释器解释成汇编指令,终再转译成 CPU 可以识别的机器指令,解释器是软件来实现的,主要是为了实现同一份 Java 字节码可以在不同的硬件平台上运行,而将汇编指令转换成机器指令由硬件直接实现,这一步速度是很快的,当然 JVM 为了提高运行效率也可以将某些热点代码(一个方法内的代码)一次全部编译成机器指令后然后在执行,也就是和解释执行对应的即时编译(JIT), JVM 启动的时候可以通过 -Xint 和 -Xcomp 来控制执行模式。
从软件层面上, class 文件被加载进虚拟机后,类信息会存放在方法区,在实际运行的时候会执行方法区中的代码,在 JVM 中所有的线程共享堆内存和方法区,而每个线程有自己独立的 Java 方法栈,本地方法栈(面向 native 方法),PC寄存器(存放线程执行位置),当调用一个方法的时候, Java 虚拟机会在当前线程对应的方法栈中压入一个栈帧,用来存放 Java 字节码操作数以及局部变量,这个方法执行完会弹出栈帧,一个线程会连续执行多个方法,对应不同的栈帧的压入和弹出,压入栈帧后就是 JVM 解释执行的过程了。
程序设计的5个底层逻辑,决定你能走多快
中断
刚刚说到, CPU 只要一上电就像一个永动机, 不停的取指令,运算,周而复始,而中断便是操作系统的灵魂,故名思议,中断就是打断 CPU 的执行过程,转而去做点别的。
例如系统执行期间发生了致命错误,需要结束执行,例如用户程序调用了一个系统调用的方法,例如mmp等,就会通过中断让 CPU 切换上下文,转到内核空间,例如一个等待用户输入的程序正在阻塞,而当用户通过键盘完成输入,内核数据已经准备好后,就会发一个中断信号,唤醒用户程序把数据从内核取走,不然内核可能会数据溢出,当磁盘报了一个致命异常,也会通过中断通知 CPU ,定时器完成时钟滴答也会发时钟中断通知 CPU 。
中断的种类,我们这里就不做细分了,中断有点类似于我们经常说的驱动编程,而这个通知机制是怎么实现的呢,硬件中断的实现通过一个导线和 CPU 相连来传输中断信号,软件上会有特定的指令,例如执行系统调用创建线程的指令,而 CPU 每执行完一个指令,就会检查中断寄存器中是否有中断,如果有就取出然后执行该中断对应的处理程序。
陷入内核 : 我们在设计软件的时候,会考虑程序上下文切换的频率,频率太高肯定会影响程序执行性能,而陷入内核是针对 CPU 而言的, CPU 的执行从用户态转向内核态,以前是用户程序在使用 CPU ,现在是内核程序在使用 CPU ,这种切换是通过系统调用产生的。
系统调用是执行操作系统底层的程序,Linux的设计者,为了保护操作系统,将进程的执行状态用内核态和用户态分开,同一个进程中,内核和用户共享同一个地址空间,一般 4G 的虚拟地址,其中 1G 给内核态, 3G 给用户态。在程序设计的时候我们要尽量减少用户态到内核态的切换,例如创建线程是一个系统调用,所以我们有了线程池的实现。
好 了,已经介绍完了实用目的、学术目的、商业及特殊需要,相信各位对“为什么会有这么多种程序设计语言”这个问题有了更深刻的理解,也可能有了更多的疑惑。 如果你有任何疑惑或者愿意和我交流,欢迎留言。对了,除了我说的三个目的之外还有没有别的创造新语言的原因?有,我自己设计了一种名为Grove的语言,用“树”来完成过程编程和lambda表达式,改天把解释器的发出来交流一下。我的目的呢?Just for fun…
不要想你能为做什么,想想你该为做什么!
今日报名合肥计算机程序设计员在哪里报名要满足什么条件考yp
合肥其他教育培训相关信息
11月19日
10月31日
9月2日
7月22日
7月17日
7月16日
7月15日
7月13日
7月12日
7月10日