1、选择一组合适的算法和数据结构;
2、编写出编译器能够有效优化的源代码;(编写程序方式中一点小小的变动,都会引起编译器优化方式的很大变化,必须了解编译器的能力和局限性,有些编程语言比其他语言容易优化得多,C语言的有些特性,如:执行指针运算和强制类型转换,使得编译器很难对它进行优化。在程序的开发和优化的过程中,我们必须考滤代码的使用方法,程序员必须在实现和维护程序的简单性与它的运行速度之间做出权衡,在代码级上,许多低级的优化往往会降低程序的可读性和模块性,使得程序容易出错,并且更难以修改和扩展。
优化程序性能的基本策略:
1、高级设计。为遇到的问题选择适当的算法和数据结构。要特别警觉,避免使用那些会渐进地产生糟糕性能的算法或编码技术
2、基本编码原则。避免限制优化的因素,这样编译器就能产生高效的代码。消除连续的函数调用。在可能时,将计算移到循环外。考虑有选择地妥协程序的模块性以获得更大的效率。消除不必要的存储器引用。引入临时变量来保存中间结果。只有在最后的值计算出来时,才将结果存放到数组或全局变量中。
3、低级优化。展开循环,降低开销,并且使得进一步优化成为可能。通过使用例如多个累积变量和重新结合等技术,找到方法提高指令级并行。用功能的风格重写条件操作,使得编译采用条件数据传送。)
3、将一个任务分成多个部分,使这些部分可以在多核和多处理器以及网络中能够并行、并发的执行。
Amdahl定律:
如果逻辑控制流在时间上重叠,就是并发的。并行与并发的区别是,并行流是并行执行的,并发流是交替执行的,在宏观上产生几个程序同时执行的现象,并发并没有在根本上提高程序的运行效率。并行需要硬件的支持,并发可以在逻辑控制流上实现。并发可以解决访问慢速I/O设备、与人交互、推迟工作到优先级较低的并发流中以降低延迟、服务多个网络客户端,并发可以利用多核CPU实现并行计算。
使用应用级并发的应用程序称为并发程序,现代操作系统提供三种基本的构造并发程序的方法:1、进程:用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信(interprocess communication, IPC)机制。2、I/O多路复用:在这种形式的并发编程中,应用程序在一个进程的上下文中显式地调度它们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态。因为程序是一个单独的进程,所以所有的流都共享同一个地址空间。3、线程:线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度。你可以把线程看成是其他两种方式的混合体,像进程流一样由内核进行调度,而像I/O多路复用流一样共享同一个虚拟地址空间。
基于进程的并发编程:关于进程的优劣:
对于在父、子进程间共享状态信息,进程有一个非常清晰的模型:共享文件表,但是不共享用户地址空间。进程有独立的地址空间即是优点也是缺点。这样一来,一个进程不可能不小心覆盖另一个进程的虚拟存储器,这就消除了许多令人迷惑的错误——这是一个明显的优点。
另一方面,独立的地址空间使得进程共享状态信息变得更加困难。为了共享信息,它们必须使用显式的IPC(进程间通信)机制。基于进程的设计的另一个缺点是,它们往往比较慢,因为进程和IPC的开销很高。
基于I/O多路复用的并发编程:I/O多路复用技术的优劣:
I/O多路复用可以用做并发事件驱动程序的基础,在事件驱动程序中,流是因为某种事件而前进的。一般概念是将逻辑流模型化为状态机。不严格地说,一个状态机就是一组状态(state)、输入事件(input event)和转移(transition),其中转移就是将状态和输入事件映射到状态。每个转移都将一个(输入状态,输入事件)对映射到一个输出状态。自循环(self-loop)是同一输入和输出状态之间的转移。通常把状态机画成有向图,其中节点表示状态,有向弧表示转移,而弧上的标号表示输入事件。一个状态机从某种初始状态开始执行。每个输入事件都会引发一个从当前状态到下一状态的转移。
基于I/O多路复用的事件驱动设计的一个优点是,它比基于进程的设计给了程序员更多的对程序行为的控制。另一个优点是,一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址空间。这使得在流之间共享数据变得容易。最后,事件驱动设计常常比基于进程的设计要高效得多,因为它们不需要进程上下文切换来调度新的流。
事件驱动设计的一个明显示的缺点就是编码复杂。随着并发粒度的减小,复杂性上升。基于事件的设计的另一个重大缺点是它们不能充分利用多核处理器。
基于线程的并发编程:
基于线程的并发编程可以看作上面两种方式的混合,相较于基于进程的并发编程,基于线程的并发编程具有一至的用户虚拟地址空间,使得信息共享较容易实现,相较于基于I/O多路复用的并发编程,基于线程的并发编程的每个逻辑流会被内核自动调度,有利于充分利用多核处理器。
线程(thread)就是运行在进程上下文中的逻辑流。线程由内核自动调度。每个线程都有自己的线程上下文(thread context),包括一个唯一的整数线程ID(Thread ID)、栈、栈指针、程序计数器、通用目的寄存器和条件码。所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间。
多线程的执行模型在某些方面和多进程的执行模型是相似的。在一些重要的方面,线程执行是不同于进程的。因为一个线程的上下文要比一个进程的上下文小得多。另一个不同就是线程不像进程那样,不是按照严格的父子层次来组织的。和一个进程相关的线程组成一个对等(线程)池(pool),独立于其他线程创建的线程。主线程和其他线程的区别仅在于它总是进程中第一个运行的线程。对等(线程)池概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止。另外,每个对等线程都能读写相同的共享数据。
Posix线程(Pthreads)是在C程序中处理线程的一个标准接口。
基于线程的事件驱动程序:使用线程提高并行性:一旦要求同步对数据的访问,事情就变得复杂得多了。
线程安全。可重入性。竞争。
2、编写出编译器能够有效优化的源代码;(编写程序方式中一点小小的变动,都会引起编译器优化方式的很大变化,必须了解编译器的能力和局限性,有些编程语言比其他语言容易优化得多,C语言的有些特性,如:执行指针运算和强制类型转换,使得编译器很难对它进行优化。在程序的开发和优化的过程中,我们必须考滤代码的使用方法,程序员必须在实现和维护程序的简单性与它的运行速度之间做出权衡,在代码级上,许多低级的优化往往会降低程序的可读性和模块性,使得程序容易出错,并且更难以修改和扩展。
优化程序性能的基本策略:
1、高级设计。为遇到的问题选择适当的算法和数据结构。要特别警觉,避免使用那些会渐进地产生糟糕性能的算法或编码技术
2、基本编码原则。避免限制优化的因素,这样编译器就能产生高效的代码。消除连续的函数调用。在可能时,将计算移到循环外。考虑有选择地妥协程序的模块性以获得更大的效率。消除不必要的存储器引用。引入临时变量来保存中间结果。只有在最后的值计算出来时,才将结果存放到数组或全局变量中。
3、低级优化。展开循环,降低开销,并且使得进一步优化成为可能。通过使用例如多个累积变量和重新结合等技术,找到方法提高指令级并行。用功能的风格重写条件操作,使得编译采用条件数据传送。)
3、将一个任务分成多个部分,使这些部分可以在多核和多处理器以及网络中能够并行、并发的执行。
Amdahl定律:
如果逻辑控制流在时间上重叠,就是并发的。并行与并发的区别是,并行流是并行执行的,并发流是交替执行的,在宏观上产生几个程序同时执行的现象,并发并没有在根本上提高程序的运行效率。并行需要硬件的支持,并发可以在逻辑控制流上实现。并发可以解决访问慢速I/O设备、与人交互、推迟工作到优先级较低的并发流中以降低延迟、服务多个网络客户端,并发可以利用多核CPU实现并行计算。
使用应用级并发的应用程序称为并发程序,现代操作系统提供三种基本的构造并发程序的方法:1、进程:用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信(interprocess communication, IPC)机制。2、I/O多路复用:在这种形式的并发编程中,应用程序在一个进程的上下文中显式地调度它们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态。因为程序是一个单独的进程,所以所有的流都共享同一个地址空间。3、线程:线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度。你可以把线程看成是其他两种方式的混合体,像进程流一样由内核进行调度,而像I/O多路复用流一样共享同一个虚拟地址空间。
基于进程的并发编程:关于进程的优劣:
对于在父、子进程间共享状态信息,进程有一个非常清晰的模型:共享文件表,但是不共享用户地址空间。进程有独立的地址空间即是优点也是缺点。这样一来,一个进程不可能不小心覆盖另一个进程的虚拟存储器,这就消除了许多令人迷惑的错误——这是一个明显的优点。
另一方面,独立的地址空间使得进程共享状态信息变得更加困难。为了共享信息,它们必须使用显式的IPC(进程间通信)机制。基于进程的设计的另一个缺点是,它们往往比较慢,因为进程和IPC的开销很高。
基于I/O多路复用的并发编程:I/O多路复用技术的优劣:
I/O多路复用可以用做并发事件驱动程序的基础,在事件驱动程序中,流是因为某种事件而前进的。一般概念是将逻辑流模型化为状态机。不严格地说,一个状态机就是一组状态(state)、输入事件(input event)和转移(transition),其中转移就是将状态和输入事件映射到状态。每个转移都将一个(输入状态,输入事件)对映射到一个输出状态。自循环(self-loop)是同一输入和输出状态之间的转移。通常把状态机画成有向图,其中节点表示状态,有向弧表示转移,而弧上的标号表示输入事件。一个状态机从某种初始状态开始执行。每个输入事件都会引发一个从当前状态到下一状态的转移。
基于I/O多路复用的事件驱动设计的一个优点是,它比基于进程的设计给了程序员更多的对程序行为的控制。另一个优点是,一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址空间。这使得在流之间共享数据变得容易。最后,事件驱动设计常常比基于进程的设计要高效得多,因为它们不需要进程上下文切换来调度新的流。
事件驱动设计的一个明显示的缺点就是编码复杂。随着并发粒度的减小,复杂性上升。基于事件的设计的另一个重大缺点是它们不能充分利用多核处理器。
基于线程的并发编程:
基于线程的并发编程可以看作上面两种方式的混合,相较于基于进程的并发编程,基于线程的并发编程具有一至的用户虚拟地址空间,使得信息共享较容易实现,相较于基于I/O多路复用的并发编程,基于线程的并发编程的每个逻辑流会被内核自动调度,有利于充分利用多核处理器。
线程(thread)就是运行在进程上下文中的逻辑流。线程由内核自动调度。每个线程都有自己的线程上下文(thread context),包括一个唯一的整数线程ID(Thread ID)、栈、栈指针、程序计数器、通用目的寄存器和条件码。所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间。
多线程的执行模型在某些方面和多进程的执行模型是相似的。在一些重要的方面,线程执行是不同于进程的。因为一个线程的上下文要比一个进程的上下文小得多。另一个不同就是线程不像进程那样,不是按照严格的父子层次来组织的。和一个进程相关的线程组成一个对等(线程)池(pool),独立于其他线程创建的线程。主线程和其他线程的区别仅在于它总是进程中第一个运行的线程。对等(线程)池概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止。另外,每个对等线程都能读写相同的共享数据。
Posix线程(Pthreads)是在C程序中处理线程的一个标准接口。
基于线程的事件驱动程序:使用线程提高并行性:一旦要求同步对数据的访问,事情就变得复杂得多了。
线程安全。可重入性。竞争。