20210210关于数据流动(2)回到旧时,是如何通过“数据共享”实现通信的,以及如何通过“数据共享”实现数据聚合的 - ziyouzy/2021blog GitHub Wiki

以前的数据共享是通过一个缓存对象实现的:

如一个map[string]NodoDo
里面会包含软件系统所设计到所有物理传感器的事实数据

他既可以通过某一个线程来更新,也可以通过好几个线程来更新**(数据聚合)**
~~他也既可以被某一个线程“取”数据,也可以被多个线程来“取数据”~~这不遵循单向调用链“设计模式”,也不遵循事件驱动“业务模式”,应该是:
他也既可以给某1个线程主动发送数据,也可以给某多个线程主动发送数据**(数据共享)**

这样来看思路一下就清晰了:

旧时无论是数据聚合与数据共享都是基于缓存(缓存+线程)才实现了其自身的设计模式
而golang的新思路则是建议基于缓存与线程这两个技术实现数据聚合,同时基于管道与线程实现数据共享

再回到过去说说具体实现方式:

共享:
先将各个独立的数据从各个独立的线程汇总到缓存,如map[string]NodoDo
再将每一个NodeDo分发给之后的各个新线程

聚合:
先将各个独立的数据从各个独立的线程汇总到缓存,如map[string]NodoDo
再将所有的NodeDo(事件)通过某种计算逻辑压缩成一个变量(事件)
最终将这个**唯一**的“东西”发到**一**个单独的线程

而新时代管道的出现则让“共享”这一环节省去了对缓存的设计,让实现“共享”变得更加的容易,更加节省系统资源

“Do not communicate by sharing memory; instead, share memory by communicating”对这句话我个人的理解是:
如果想把某个线程的数据分发到另一个或者另外几个线程,你不该通过设计、创建并使用某种缓存对象的方式实现
在这里sharing memory是一个动词,一种动作或方式;communicate是一名字,一种结果或目的

但是某一个线程里的缓存对象,你可以设计(要求)多个线程发来你需要的数据到这个缓存所在的线程,从而在缓存所在的线程实现数据的更新
在这里share memory是一名字,一种结果或目的;communicating是一个动词,一种动作或方式

而这在我看来只是半句话
因为当你实现了“通过管道与线程实现通信”后接下来你要干什么?
以及当你实现了“通过通信维护了(某个缓存对象)共享内存”后接下来你又要干什么?
答案似乎是:
首先,通信必然是通过管道与线程来实现的,同时通信也分为扇出与扇入两个分型
借助通信(管道+线程)可以直接实现数据流动中的“分流操作”(基于扇出分型)
借助通信(管道+线程)可以实现数据流动中的“简单支流聚合操作”(基于扇入分型)
借助通信和缓存(管道+线程+缓存)可以实现数据流动中的“复杂支流聚合操作”(基于扇入分型)

结论:不该用数据共享实现通信的扇出,但是可以用通信扇入实现数据共享

再说的细致一点:golang中不该基于管道、线程、缓存这三个技术实现通信的扇出(只用管道和线程就够了),而根据业务复杂程度可以挑选管道、线程、缓存来实现通信的扇入

ps:
将一个数据基于管道扇出到不同线程=数据分发技术
将多个数据先基于管道扇入到某个独立线程=数据聚合技术(同时在这个独立线程中很可能也需要配合缓存技术才能实现最好的效果)

ps2:管道,线程,缓存是三个地位平等的技术,而通信则是管道加线程所实现的技术,扇出/入属于通信的分型