首页 理论教育 时序数据流:完美软件开发方法

时序数据流:完美软件开发方法

时间:2023-11-21 理论教育 版权反馈
【摘要】:软件是一种固化的思维→思维的固化体现为概念和逻辑的固化→为保证简单性,时序自身要尽可能简单→如果多线程这样的手段使概念的实例处在很难理解的状态,逻辑关系将变得复杂→使时序复杂化时,要有关键理由。对时序影响很大的一个因素是并行,并行的一个常见实现方法是启用多线程。这时虽然启用了多线程,但实际执行起来这些线程是串行的。

时序数据流:完美软件开发方法

软件是一种固化的思维→思维的固化体现为概念和逻辑的固化→为保证简单性,时序自身要尽可能简单→如果线程这样的手段使概念的实例处在很难理解的状态,逻辑关系将变得复杂→使时序复杂化时,要有关键理由。

所谓时序,即动作的先后顺序。

时空的特征决定了这世界上大多的事情皆有因果,也决定了程序中凡事必有先后。当我们明确了先做什么,再做什么,最后做什么之后,我们才能对事情真正有所把握。不管采用什么设计方法,都要让这类路线尽可能明晰。唯其如此,程序才更容易懂,因为这是正常人最基本的认知世界的方式。

对时序影响很大的一个因素是并行,并行的一个常见实现方法是启用多线程(或多进程)。多线程类程序之所以难写,不在于本身的机制或同步多么难以掌握,而在于并发使整个程序中的逻辑变得更加复杂。时序背后的东西是信息的流向。

关于这点可能很多人心存疑问,并会以为在面向对象的世界里,这点已经无关紧要,但其实不然,明确信息流一如既往的重要。

正是在信息流动的过程中,概念才能完成衍化、归并,并最终再确定的过程。为理解这点,回顾计算机最基本的模型也许是有必要的,如图7-8所示。

978-7-111-42626-4-Chapter07-23.jpg

图7-8 计算机的基本体系结构

改自《深入理解计算机系统》,在冯·诺依曼体系中,键盘和鼠标被称为输入设备,显示器被称为输出设备

这个模型提醒我们一个最为基本的事实,不管内部通过什么样的手段(OO或其他)做了多少细节处理,当人们使用计算机时,通常的过程是,通过输入一些东西(大多时候用键盘和鼠标),并希望获取一些输出(大多时候通过显示器),而输入、输出必不相同。

人们使用计算机的目的,也正是软件的根本使命。软件对用户输入进行抽象,分割,而后按照指定的步骤进行相应处理,最终,把结果返回给用户。而处理步骤所体现的正是信息的流向。不管我们使用什么样的设计方法(面向对象或其他),信息流向越复杂,信息的分散度越高,软件也就越难懂,软件的维护也就会越发困难。

我们常说的顺序,分支,选择,优先顺位处理则是时序的一种具体表现形式。优先顺位处理关系是指抢占,一个典型的应用是操作系统中的线程调度。大多情况下,并行对复杂度影响过大,并间接导致测试困难——多线程或多进程导致的问题往往是有时发生,有时不发生,一般的测试手段并不足以发现这类问题。所以原则上应该尽可能不用,除非收益足够大。或者说在满足需求的前提下,线程数和进程数应该尽可能少。

以多线程和多进程而论,确定“什么时候适合使用这种技术”是比“怎么使用这项技术”困难得多的事情。

现实中人们往往对事件,信号灯等同步处理手段关注过多,而对究竟应不应该启用多线程/进程关注得太少。这里来简单做个总结,对于下面这些场景,一般来讲启用多线程/进程是合适的。

●数据很容易分割,处理不同数据时彼此间没有什么交互。比如说,有10万个文件需要处理,每个文件的处理彼此独立。这时候显然要做并行,这样最终数据处理速度将依赖于并行分布的程度。这好像很简单,但却触发了MapReduce这样著名的模型(参见《软件随想录》)。在待处理数据持续增长的情形下,如果不启用并行,那几乎没有办法保证速度不会下降,这并不是单纯靠优化算法可以解决的问题。(www.xing528.com)

●监控设备响应(端口监视也应该属于这个类别)。这时候我们会希望能及时响应设备的事件,而不希望设备上的数据采集和对数据的处理彼此干涉。比如,Windows中就单独建立了Raw Input Thread(RIT)来监控整个系统的键盘和鼠标消息,而后再分发给各个进程中的线程。(详见《Windows核心编程》)。

●优化UI响应速度。比如,用文档编辑器打开大文件时,如果不分离UI响应和实际处理,UI会挂起,很典型的应用是进度条的处理。使用了MVC(Model-View-Controller)模式的应用中大多时候可以适用这条,因为很多时候都需要View和Controller总是保持响应。

●待处理的请求天生就是并行的。比如,当浏览不同网站时,不同的网站的显示会在不同的窗口中处理,这类处理天生就是并行的,既可以用多线程也可以用多进程。客户/服务器体系也是这类情形。

●计算量很大,并且算法可以分割。有些传说中的领域(大气模拟、基因工程等)事实上是并行计算的主战场,比如,在展示MPI(Message Passing Interface)的使用时,经常使用的计算π的例子,就是如此。但这离通用软件开发的距离就有点远,知之不详,这里就不列了。

这个列表应该进一步加长,但限于精力,眼下却只能列这么多了。

对于多线程的误用,在MSDN上可以找到一份很好的总结,这里提取几个典型的。

●锁争用和顺序执行。这时虽然启用了多线程,但实际执行起来这些线程是串行的。

●过度订阅。如果系统的核数远少于线程数,同时启动很多个线程,时间往往会浪费在抢占上。

●I/O效率低。多线程被用来做频繁的I/O操作,这会导致很多时间开销在I/O操作上。并行的种类

为并行分类并不是很容易的事,这里只介绍一种最简单的,依据内存架构对并行进行分类的方法。依据内存架构,并行可以分为3类。

Shared Memory:常说的多线程即是这一类,比较有名的实现是OpenMP。

Distributed Memory:如果多台PC组合起来进行并行计算那就是这一类。比较有名的实现是MPI。

Hybrid Distributed-Shared Memory:如果多台PC进行分布,每台PC上还启用多核,那就是这类。

有人似乎还想进一步区分并行和并发,这就有点微妙了,这里不做这类区分,请读者自行研究吧。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈