除了线程池:java并发并不像你想的那么糟糕

有很多的传言流传着关于并发更新的消息,然而,许多开发人员还没有时间把过多的注意力都放在上面。在这篇文章中,我们将带你了解Java 8 streams, Hadoop, Apache Spark, Quasar fibers以及响应式编程,让你迅速入门,尤其是如果你不经常用他们的话。一句话,它并不遥远,它就在我们身边。

我们该怎么办?

当谈到并发,一个很好的方式来形容当前的问题是来回答几个小问题以便更好的了解它:

1.它是一个数据处理任务么?如果是这样的话,它可以分解为独立的任务单元么?

2.操作系统、虚拟机和你的代码之间的关系是什么?(本地线程VS轻量级线程)

3.有多少机器和处理器参与?(单核和多核)

让我们带着问题,一起找出每个问题的最佳答案吧。

从线程池到并行流

在java8中,我们了解到新的流api接口,它允许应用聚集操作,如筛选、排序或者映射数据流。另一件流允许我们的事情是并行操作在多核机器上的应用。并行流-通过把Fork/Join框架引入Java7将线程间的工作分离。java6并发库,我们看到了ExecutorService创建和处理我们的工作线程池,这不得不说是个进步。

Fork/Join也建立在ExecutorService之上,从传统的线程池看主要的区别是他们如何在线程和支持多核的机器间分配工作。用一个简单的ExecutorService你能完全控制工作线程之间的负载分布,确立每个任务的大小以便线程来处理。而Fork/Join,恰好有个work-stealing算法分配线程间的负载。简而言之,这允许大型任务可以被分成更小单元,并在不同的线程间处理,最终我们可以知道-它是为了平衡线程间的工作,然而,这并不是万能的。

有时并行流会减慢你速度的,所以你需要多想想,在你的方法中使用parallelStream()会导致瓶颈和减速(在我们基准测试中跑慢了约15%左右),假设我们已经运行多个线程,在其中一些我们使用parallelStream(),在线程池中添加越来越多的线程。这可以很容易变成超过我们的核心处理,由于增加了上下文转换一切都慢下来了。

小结:在单个机器上并行流分离处理线程在某种程度上分配你的核心间的负载。然而,如果你想要高效的使用它们记住硬件是关键,与你的机器可以处理更多的线程相比。

Apache Hadoop and Apache Spark

并发

接下来谈多核机器,pb级数据和任务,这跟所有从twitter提到的java或重载机器学习算法类似。当谈到Hadoop,不得不说这个应用广泛的框架及它的组件:Hadoop分布式文件系统(HDFS)、资源管理平台(YARN)、数据处理模块(MapReduce)和其他所需的类库和工具(Common)。在这些组件上层还有一些其他很受欢迎的可选工具,比如运行在HDFS上的数据库(Hbase),查询语言平台(Pig)和数据仓库基础结构(Hive)。

Apache Spark 作为一种新数据处理模块,以内存性能和快速执行的弹性分布式数据集(RDDS)而出名,不像Hadoop MapReduce不能高效的使用内存(和磁盘)操作。最新被Databricks公布的数据显示当用少于10倍节点的时候,在对一个字节的数据排序中Spark是Hadoop的三倍。

典型的Hadoop应用方面在数据查询,而Spark以它的快速运行时机器学习算法越来越出名。但这只是冰山一角,Databricks如是说:”Spark 使应用程序在Hadoop集群中运行在内存中快100倍,当运行在磁盘中时甚至快10倍”。

小结:Spark是在Hadoop生态系统中的后起之秀,有一个常见的误解是我们现在经常谈它一些不合作或竞争的事情,但是我认为我们在这正在看到这个框架的发展。

Quasar fibers

我们有机会运行在Hadoop,现在让我们回到单机。事实上,在java多线程应用程序和集中在单线程中,让我们眼光再长远些。就我们而言,HotSpot JVM线程与本地系统线程相同,持有一个线程并且运行在”虚拟“线程中,这在fibers中都包含的。Java没有原生的fibers支持,但是不要担心,Quasar解决了我们的问题。

Quasar是一个开源的JVM库,它支持fibers(也称为轻量级线程),并且还充当框架的角色,在后面中我会提到。在这上下文转换是它本质的名字。当我们核心数量有限,一旦本地线程数量越大我们就会收到越来越多的上下文开销。一个解决这个问题的方式是fibers,使用单线程支持”多线程“,这看起来像threadception的一个实例。

fibers还可以被视为一个从线程池的进化,当我们通过应用并行流的时候避开了线程过载的危险。他们更容易衡量线程和允许令人可观的并行”light“线程数量。他们不是为了取代线程,而是应该用于那些相对来说经常使用的代码块,就像他们作为真正的异步线程。

小结:并行领域在Java并发性中正提供一种新的思路,虽然还没有版本发布,但是值得一试。

Actor和响应式编程

在响应式的官方言论中,最新的释义有4原则:相应,有弹性,灵活性和消息驱动。这基本意味着快速、容错、可伸缩的和支持非阻塞通信。

让我们看看Akka Actor是如果支持它的吧。简单来讲Actor有一个状态和一个特定的行为,通过交换消息沟通彼此的邮箱,一个Actor系统作为一个整体应该被每个应用程序创建,拥有一个层次结构将任务分解成更小的任务以便每个角色最多只有一个监督的角色。一个角色也可以处理这个任务,通过委托给另一个角色将其进一步分解或在实例失败的情况下,将它反馈给它的监督者。无论哪种方式,消息不应该包括行为或者共享可变的状态,每个角色都有一个独立的状态和行为。

它是一个从大多数开发者在使用的并发模型的思考模式的转移。尽管它的起源是从70年代,但是为了适应现代应用程序的要求,直到最近几年它才复苏。并行领域的Quasar也支持Actor,实现的主要区别在与fibers/轻量级线程。

小结:相反的,Actor模型需要管理线程池,让它远离使用工具包。今天各种关于更多核心的高并发系统中应用程序处理能力的那些老话题,说实话我们是可以处理的。

总结

关于使用并发或者并行算法,我们今天通过介绍4种方法来解决问题来应对你需要的场景。希望这有助于激起你的兴趣,以及在这大谈并发话题的现在开拓下你的视野。除了线程池,这是种趋势通过将它委托给语言及它的工具-关注新的技术并应用它而不是花费无数个小时解决竞态条件和锁。

英文原文链接

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓