快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

万博体育app官方网_酒文化网进入



在并发性期间,带有 4、6 和 16 个处置惩罚器核心的芯片变得很普遍,而且在不久的将来,我们会看到带有上百以致上千个核心的芯片。这种处置惩罚能力蕴含着伟大年夜的可能性,但对付软件开拓职员来说,它也带来了寻衅。最大年夜限度地使用这些闪灼新核的需求推动了对并发性、状态治理和为两者构建的编程说话的关注热潮。

Groovy、Scala 和 Clojure 等 JVM 说话满意了这些需求。这三种都是较新的说话,运行于高度优化的 JVM 之上,可以应用 Java 1.5 中新增的强大年夜的 Java 并发库。只管每种说话基于其道理采纳不合的措施,不过它们都积极支持并发编程。

在本文中,我们将应用 GPars,一种基于 Groovy 的并发库,来反省模型以便办理并发性问题,比如后台处置惩罚、并行处置惩罚、状态治理和线程和谐。

为何选择 Groovy ?为何选择 GPars ?

Groovy 是运行于 JVM 之上的一种动态说话。基于 Java 说话,Groovy 移除了 Java 代码中的大年夜量正式语法,并添加了来自其他编程说话的有用特点。Groovy 的强大年夜特点之一是它容许编程职员轻松创建基于 Groovy 的 万博体育app官方网DSL。

GPars 或 Groovy Parallel Systems 是一种 万博体育app官方网Groovy 并发库,捕捉并发性和和谐模型作为 DSL。GPars 的构思源自其他说话的一些最受迎接的并发性和和谐模型,包括:

来自 Java 说话的 executors 和 fork/join

来自 Erlang 和 Scala 的 actors

来自 Clojure 的 agents

来自 Oz 的数据流变量

Groovy 和 GPars 的结合成为展示各类并发性措施的抱负万博体育app官方网之选。以致不认识 Groovy 的 Java 开拓职员也能轻松关注相关评论争论,由于 Groovy 的语法以 Java 说话为根基。本文中的示例基于 Groovy 1.7 和 GPars 0.10。

后台和并行处置惩罚

一个常见的机能难题是必要等待 I/O。I/O 可能涉及到从一个磁盘、一个 web 办事或以致是一名用户读取数据。当一个线程在等待 I/O 的历程中被阻拦时,将等待中的线程与原始履行线程分分开来将会很有用,这将使它能继承事情。因为这种等待是在后台发生的,以是我们称这种技巧为 后台处置惩罚。

例如,假设我们必要这样一个法度榜样,即调用 Twitter API 来找到针对多少 JVM 说话的最新 tweets 并将它们打印出来。Groovy 能够应用 Java 库 twitter4j 很轻易就编写出这样的法度榜样,如清单 1 所示:

清单 1. 串行读取 tweets (langTweets.groovy)

import twitter4j.Twitter

import twitter4j.Query

@Grab(group='net.homeip.yusuke', module='twitter4j', version='2.0.10')

def recentTweets(api, queryStr) {

query = new Query(queryStr)

query.rpp = 5  // tweets to return

query.lang = "en"  // language

tweets = api.search(query).tweets

threadName = Thread.currentThread().name

tweets.collect {

"[${threadName}-${queryStr}] @${it.f万博体育app官方网romUser}: ${it.text}"

}

}

def api = new Twitter()

['#erlang','#scala','#clojure'].each {

tweets = recentTweets(api, it)

tweets.each {

println "${it}"

}

}

在 清单 1中,我首先应用了 Groovy Grape来捕获 twitter4j 库依附性。然后定义了一个 recentTweets措施来吸收查询字符串并履行该查询,返回一列款式化为字符串的 tweets。着末,我遍历了标记列表中的每个标记,获取了 tweets 并将它们打印出来。因为未应用线程,该代码串行履行每个搜索,如图 1 所示:

图 1. 串行读取 tweets

并行处置惩罚

假如 清单 1中的法度榜样静候等待,它也可能不止等待一个处置惩罚。假如我将每个远程哀求放入一个后台线程中,法度榜样会并行等待每个相应查询,如图 2 所示:

图 2. 并行读取 tweets

GPars Executors DSL 使得我们更轻易将 清单 1中的法度榜样从串行处置惩罚转换为并行处置惩罚,如清单 2 所示:

清单 2. 并行读取 tweets (langTweetsParallel.groovy)

import twitter4j.Twitter

import twitter4j.Query

import groovyx.gpars.GParsExecutorsPool

@Grab(group='net.homeip.yusuke', module='twitter4j', version='2.0.10')

@Grab(group='org.codehaus.gpars', module='gpars', version='0.10')

def recentTweets(api, queryStr) {

query = new Query(queryStr)

query.rpp = 5  // tweets to return

query.lang = "en"  // l万博体育app官方网anguage

tweets = api.search(query).tweets

threadName = Thread.currentThread().name

tweets.collect {

"[${threadName}-${queryStr}] @${it.fromUser}: ${it.text}"

}

}

def api = new Twitter()

GParsExecutorsPool.withPool {

def retrieveTweets = { query ->

tweets = recentTweets(api, query)

tweets.each {

println "${it}"

}

}

['#erlang','#scala','#clojure'].each {

retrieveTweets.callAsync(it)

}

}

我应用 Executors DSL 为 GParsExecutorsPool添加了一段 import语句,并应用 Groovy Grape 依附性系统添加了一段 Grab语句来捕获 GPars 库。然后我引入了一个 GParsExecutorsPool.withPool块,这将增强块中的代码以添加额外功能。在 Groovy 中,可以应用 call措施来调用闭包。GParsExecutorsPool将在底层内存池中作为义务履行经由过程 call 措施调用的闭包。此外,GParsExecutorsPool经由过程一个 callAsync措施增强闭包,被调用后该措施在无壅闭的环境下急速返回。在本例中,我包装了我的 tweet 搜索并将操作包装到一个闭包中,然后为每个查询异步调用它。

因为 GPars 将这些义务分配给了一批功课员,我现在可以并行履行我的所有搜索了(只要内存池足够大年夜)。我也可以并行处置惩罚每个查询所得结果,在其到达时打印到屏幕。

该例展示了后台处置惩罚能够前进机能和相应能力的两种要领:I/O 等待并行完成,依附于该 I/O 的处置惩罚也并行发生。

Executors

您可能想知道什么是 executor,GParsExecutorsPool中的后台处置惩罚若何事情。Executor实际上是 Java 5 中引入的 java.util.concurrent库的一部分。java.util.concurrent.Executor接口仅有一个措施:execute(Runnable)。它存在的目的在于将义务的提交与一个 Executor实现中义务的实际履行要领分分开来。

java.util.concurrent.Executors类供给许多有用的措施来创建各类不合的线程池类型支持的 Executor实例。GParsExecutorsPool默认应用一个含守护进程线程和固定命目线程的一个线程池(Runtime.getRuntime().availableProcessors() + 1)。当默认设置分歧合时,要变动线程池大年夜小、应用一个自定义 ThreadFactory或指定现有的全部 Executor池(withExistingPool)很简单。

要变动线程数,我可以将 GParsExecutorsPool线程计数通报给 withPool措施,如清单 3 所示:

清单 3. 应用线程计数启动一个 Executor 池

GParsExecutorsPool.withPool(8) {

// ...

}

或者假如我想通报一个具有专门命名线程的自定义线程工厂,我可以像清单 4 这样做。

清单 4. 应用自定义线程工厂启动一个 Executor 池

def threadCounter = new AtomicLong(0)

def threadFactory = {Runnable runnable ->

Thread thread = new Thread(runnable)

id = threadCounter.getAndIncrement()

thread.setName("thread ${id}")

return thread

} as ThreadFactory

def api = new Twitter()

GParsExecutorsPool.withPool(2, threadFactory) {

// ...

}

async和 callAsync措施不阻拦线程并急速返回一个 Future工具来表示异步谋略的未来结果。接管者可以要求 Future阻拦线程,直至一个结果就绪,检测查看它是否完成并取消谋略指令,或反省是否有其他进程取消了它。与 Executor接口一样,Future类是底层 java.util.concurrent包的一部分。

CPU 的并行性

在后台处置惩罚示例中,您懂得了让一个法度榜样并行等待多个 I/O 密集型义务(而非串行处置惩罚它们)的好处。应用一批功课员来并行履行多个义务对 CPU 密集型义务也大年夜有裨益。

您的利用法度榜样的两个紧张方面影响着它可以吸收的并行度,是以您具有的编程选项包括:

义务粒度,即义务在光阴或数据上的范围

义务依附性,即平日存在于义务之间的依附关系的数量

两个方面存在于一个状态集上,且在拟订一个办理规划之前斟酌该状态集上的问题所在是很有用的。例如,一个法度榜样的义务粒度可由大年夜型事务级事情定义,它也可以由大年夜型数据集一小部分(整幅图像的几个像素)中的多个简短的谋略指令组成。因为随意率性事情量的一个线程或进程的高低文切换涉及到的开销较大年夜,小粒度级的系统每每效率低下且蒙受低机能问题。基于义务粒度的批处置惩罚是为您的系统找到最佳机能点的一种措施。

依附性较少的义务平日被描述为 “高度平行”,即太轻易将它们分成多个并行义务了。范例的例子包括图形处置惩罚、强力搜索、分形和粒子模拟。任何处置惩罚或转换大年夜批敕令或文件的营业处置惩罚法度榜样也可归入这一类。

Executor 行列步队争用

我们已做生意量了若何应用 GPars 将义务推入 Executor池的机理。不过,最好要记着,Executor是在 2005 年某个时刻添加到 Java 2 Platform、Standard Edition (J2SE) 的。它们是为相对少数的核心(2 到 8 个)而调优的,这些核心运行粗粒度的、可能会阻拦具有较少义务相关性的事务型义务。Executor是在单个传入的事情行列步队由多个事情线程共享的环境下实现的。

对付该模型的一个关键问题是增添事情线程数会加剧对事情行列步队的争用(如图 3 所示)。这种争用终极会随线程和核心的增多而成为一个可伸缩性瓶颈。

图 3. Executor 行列步队争用

Executor行列步队的一个替代项是 fork/join 框架,该框架今朝存有 JSR 166y 掩护更新,且会在 JDK 7 中正式引入 Java 平台。Fork/join 是为运行细粒度谋略义务的大年夜量并发义务而调优的。

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

您可能还会对下面的文章感兴趣: