modelandview找不到视图_处理视图

好吧,既然已经说了两个视图了:

in nek:开发视图​zhuanlan.zhihu.com

in nek:概念视图​zhuanlan.zhihu.com

我们就接着往下说吧,我们再谈谈处理视图(Process View)。看了前面两个视图的介绍,读者应该已经注意到了,所谓4+1视图,其实就是4个不同的设计角度的逻辑,开发视图是写成的那个程序,概念视图是使用的那个逻辑,部署视图是运行的方法,处理视图我们一会儿再说。我们写的程序是平的,一句一句的,逻辑都组合到一起了,部分逻辑链的独立信息被丢失了(好比你在白纸上盖戳,只盖一个你是看得见是什么的,如果盖多个,部分信息就丢失了,至少不明显了),比如只看到你的receive_pkg()函数里面写了一个日志,你就没法知道“用户是否可以跟踪关键消息的时延”这个逻辑,你得单独找好几个时延跟踪点,单独看它们,你才知道你有足够的数据可以看到时延。所以你只有代码是不行的。你需要其他平面建独立的逻辑链。4大视图并不是所有的视角(及其逻辑链),但确实是非常重要和基本的视角。而Use Case是相对支离破碎的用户使用场景,我们把这些支离破碎的场景组合起来,映射为4大视图中的行为,就大概规范住了一个系统的设计方向,就可以比较放心地进入下一层设计逻辑的细节了。

Process View,是讨论“处理过程”的视图。有人把它翻译成“进程视图”(Process在某些场合也是操作系统“进程”的意思),这显然翻译错了。但它确实和“进程”有那么一丁点关系。

处理视图讨论的是逻辑系统的“驱动”问题。所有程序,包括硬化的程序(比如一个PCIE的Bridge),都是一个逻辑系统,是有一定的先后关系的。先把a加上b,然后把结果做一个开方,然后取反写到d上……这总是有一个先后关系的,这才是一个逻辑系统。

但单纯的逻辑并不会“动”,就好比汽车轮子本身可以动,但没有引擎,它不会动。

逻辑是一样的,要让逻辑运动起来,你要一个动力源。比如你的头脑。一个连续的逻辑,需要一个连续的动力源。如果有两个动力源,两者就会有一个匹配的关系。类比汽车,如果四个轮子有4个不同速度的引擎,你非翻车不可。对于前面提到的逻辑问题,如果我们用两个头脑来算a加上b和开方取反这两个动作,双方有没有协商,这个计算就乱了。

处理视图解决的就是这么个关系,它分析的是你有多少个头脑,这些头脑怎么配合完成需要的计算。这个问题,编模块的时候想不清楚,概念视图,开发视图等也考虑不到。但你做这些设计都受这个打算的影响。所以它很重要,缺乏经验的工程师甚至不知道该怎么入题。

所以我见过有人是每个模块自动创建一个线程和一个队列,主线程启动所有这些线程,负责输入的模块(比如从网络上读数据,从磁盘读数据等),读了数据往下一个模块的队列里丢,这样就构成整个系统了。

这是一种典型的把两个逻辑Mass到一起了。怎么分模块,这很大程序上是概念视图和开发视图的事情。而怎么决定有多少线程,这是业务压力的问题。把两个逻辑联动在一起,系统就失去解决问题的活性了,动了这里那里就跟着动了,这怎么都做不好。

如果我们从IO拿数据,然后处理这些数据,然后扔到输出上。这是个串行的逻辑。从处理的角度,你就只能容得下一个“动力源”,多了不会让逻辑更快。你放三个函数(可以分属三个模块),调完一个调下一个,这只有函数调用的成本。你放三个线程,每个线程都有时间片切换成本(线程多了会进一步恶化),线程间有同步成本(这还会造成更大的时延和确切性下降)。这变成自己给自己找麻烦了。

在处理视图的设计上,我们一般认为函数调用是“硬(同步)关联”,用这种关联连接在一起的一段逻辑,只能容得下一个引擎,这组逻辑和它们所属的引擎系统,我们称为一个“动力单元”。而“队列”,是“软(异步)关联”,它可以匹配两个“动力单元”的速率不同步问题。每个动力单元,都被需求所绑定,我们设计的时候仍使用“不为天下先”的策略,不到迫不得已,不去增加动力单元。

请注意,动力单元不是模块,它和你的软件模块是交叉的关系。

什么时候我们值得增加动力单元呢?——两种情况:第一种是你可以,而且有必要分开你的动力源的时候。比如,你从IO拿到10组独立的数据,每组都要花很长才能完成,而你有超过一个CPU,这好办,你有多少个CPU,就分开多少份,每份负责一组,然后最后聚合回写就好了。或者你同时还有些维护工作要做,独立放一个线程,和你的主逻辑链分开,这样就可以了。

这些例子都满足前面说的被现实驱动的条件:

你可以:你的数据是互相独立的,逻辑上本身就没有硬关联

你有必要:你有多个CPU,你要利用他们的能力。或者你的逻辑链基本上不和别人重叠。复用驱动源反而增加逻辑。

但我们必须清楚,增加动力单元增加成本(比如你最后聚合会需要重新排队和调度),更多时候,我们看到的问题是,因为线程的调度逻辑在你控制之外,你会调来调去都调不好,加高一个线程的优先级,反而导致它得不到调度的事情很容易发生的。所以,如果你知道你要先做什么,后做什么,就好好用独立的动力单元来干,不要依赖操作系统的调度器。操作系统的调度根本不知道你要干什么,你肯定是干不过你的。

另一种情况,你的计算属性不一样,比如我见过一种产品,包含有很多向量计算,他们就把标量计算集中的算法归结为一个线程,向量计算集中的算法归结到另一个线程,然后分别聚合到不同的CPU/GPU的线程中执行,这也会产生多个不同的动力单元。

所以,其实处理视图也没有什么特别的,用到的UML工具和其他视图(比如概念视图)也没有什么两样。你其实就是要定义:

  1. 你有哪些动力源(或者动力模块)。(注意,和其他视图一样,你可以抽象的。)
  2. 模块如何被动力源所驱动。
  3. 动力源之间同步的方法是什么。

我们值得注意的是,动力源可以非常广泛的,线程,进程,服务,服务器,Signal/Interrupt/SoftIRQ/Tasklet Handler,Task,Timer。都可以是动力源,只是他们的成本,行为,同步方法不一样而已。这就完全看你对系统的认识程度了。

最后给个例子吧,比如前面这个IO的例子,光作为图示例子我们可能可以这样建模:

fdec460bbb3906cd59b74960678789c8.png

当然,正如我们一贯说的,图不重要,重要的是你的逻辑是什么,不要指望就这幅图就叫“处理视图”了。

实际设计中我看到的情况常常更多是(故意的)忘掉该有这个视图,特别是在增加新功能的时候。因为这又是个脏问题。比如在前面这个例子里,可能你本来好好的,现在发现呢,系统要关闭部分节点,已有的任务要迁移到其他还活着的节点上。好了,这种就是典型的商业级脏问题,因为它涉及到已经完成的任务怎么办,完成了一半的任务怎么办,IO读出来了,但还没有投入运行的任务怎么办。哪些可以拿走,哪些不能拿走,什么时候可以叫停这些“边缘”问题。某些工程师就开始假装不知道了,简单把数据一拷贝,任务在另一个节点上重新启动一下,测试一把——刚好没事儿!搞定!

好吧,每次说到最后都说这个也没有意思……


上面说的是架构或者系统一级的情况。在模块一级,我们常常面对的是另一个问题:系统的处理模型已经定了,我们怎么给我们的模块加功能。比如我平时见的最多的Linux驱动的模型,你准备增加一个系统调用,修改一下你的驱动配置。这同样需要处理视图来理清你的线程模型:

  1. 系统调用是线程上下文,这也意味这如果多个线程同时来访问,你有可能有互斥的问题。
  2. 如果你还有内核线程和中断上下文在起作用,那么这个问题要考虑的就更多了。
  3. 但仅仅考虑互斥问题是不够的,因为这里还有一个性能问题,如果你的互斥部分太大,阿姆达的原理就开始起作用了。你需要想办法把执行流Hash开。
  4. 需要把执行流Hash开,你就开始需要Session,Context这种概念了。但一但你引入这种概念,你就会引入相关的动态数据结构,然后你就面对这个数据结构的释放问题。要解决这个问题,你就会需要非常小心地设计这个“什么时候停止线程,什么时候停止业务,什么时候释放资源”的问题。然后使用计数,mutex,spinlock这些问题就都起来了。

这里不是要重写一次Linux Locking Book,这里是要提醒你:处理视图可以很复杂,但没有这个设计,你那些拷贝到设计文档中的代码再多,你的处理视图逻辑都是没有设计的。如果你开始修改一个这样的模块,而你还没有一个上级设计给你的处理视图模型,你就要自己还原这个模型,然后讨论你加入的功能是否是可行的。否则设计就是不完整和有漏洞的。

关键是,一旦模块中加入了你这样的设计,原来的逻辑就无法还原了,后面你再问我:为什么偶尔会死机呢?怎么修呢?——它么我怎么知道?你已经成了一团乱麻了,我又不是神仙,怎么知道破镜怎么重圆啊?泼水怎么回回收啊?你还不如重新买一个镜子,重装一盘水呢。


最后补充两句,本文是这个系列的最后一篇:

in nek:开发视图​zhuanlan.zhihu.com
in nek:概念视图​zhuanlan.zhihu.com

整个系列都是为这个文档服务的:

in nek:从香农熵谈设计文档写作​zhuanlan.zhihu.com

同时,是的,不会有《部署视图》或者《用例视图》这些东西了,如果你看了这三篇你还觉得需要说说《部署视图》,那么,就算我写了,你也一样听不进去。

这也许算是“大成若缺”的一个例子?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值