并发模型与分布式系统的相似性
并发模型与分布式系统的相似性
并发系统可以使用不同的并发模型实现。并发模型可以指定任务所需的线程数量。不同的模型有不同切分任务的方法和线程间的通信与交互。
本文中的并发模型与分布式系统中的使用的不同架构相类似。在并发系统中会线程间的交互,而分布式系统中有不同的处理进程交互。线程和进程非常相似,这可能是为什么不同并发模型和不同的分布式架构如此相似的原因了。
当然分布式系统可能会网络中断、宕机等问题。但是并发系统也可能出现CPU、网络中断以及磁盘失效等问题。但这并不影响他们互相借鉴,比如,线程的分工合作类比分布式系统中的负载均衡。另外错误处理机制也很类似,比如,日志、失败恢复等。
Parallel Workers
模型图
简单来说,就是工头会把任务切分给不同的工人,工人们同时开始工作。可以认为,一个worker就是一个线程。
这个并行工作的并发模型是在java应用中最常见的。 java.util.concurrent Java package中的许多并发工具类就是根据这个模型设计的。甚至还能在JAVA EE应用服务器上寻到它的一丝踪迹。
好处:
简答易懂,必要时只需要增加线程数量就可以了。
比如网络爬虫,可能每个核上就只有几个线程,为了充分利用CPU,你可以增加线程,就这样。
坏处:
- 访问公共数据
其实,这个模型实现起来还是比较复杂的,并没有说的那么简单。因为这些线程有时候需要访问一些公共的数据,要么是内存中的,要么是数据库中。
一旦这么一搞,就变得复杂了。各个线程访问这些公共数据,就需要保证线程安全,避免出现竞争条件、死锁等并发问题。
另外,等待访问公共数据的线程有可能会死掉,同时不同线程还会发生数据争抢。有些非阻塞的并发算法确实会减少竞争,提高效率,但是实现起来还是比较困难的。
一个解决方案是把数据写到磁盘上持久化,这样可以保存不同的历史版本。因此,多个线程访问同一持久数据资源时,如果一个线程修改了,那这个线程就获取修改的版本,而其它的数据仍然会访问或者获取原有旧的没有发生改变的数据。Scala语言就可以这么干。
这个方案看起来很好,但是读写磁盘是非常麻烦的,所以可想而知,执行效果也是堪忧。
比如,一个永久化即存储在磁盘上的LinkedList在首部添加了一个新元素,并返回新元素的引用,但是其它线程仍然保持之前首部元素的引用。另外LinkedList的内存空间并不连续,所以使用链表结果不太可能,反而数组访问起来更快。
- 无状态
因为上述问题,线程每次都需要重读获取最新数据。不管数据在哪内存还是外部数据库中,都是如此。而这意味着速度变慢,尤其是在外部数据库里的时候。
- 任务执行顺序不稳定
Job A可能在Job B之前先执行,但是有可能Job B反而先执行。所以Jobs很可能在操作系统中执行顺序并不是和开始时间一致的。
流水线式并发模型
模型图
每个worker运行在自己的线程上,且不需要与其他worker共享什么。或者说是,无共享并发模型。
使用这种并发模型的系统通常是为了实现NIO.NIO是指开始一个IO操作时(比如读文件)这个worker并不需要等待整个IO操作完成。要知道IO操作是比较耗时的,如果等待完成对于CPU来说是一种浪费。当这个IO操作完成时,IO的结果就会被传递到另一个worker
未完…
http://tutorials.jenkov.com/java-concurrency/concurrency-models.html#reactive-event-driven-systems