将GPars循环收集到Map

时间:2018-03-01 16:41:27

标签: groovy gpars

我需要迭代List并为每个项目运行一个耗时的操作,然后将其结果收集到地图中,如下所示:

List<String> strings = ['foo', 'bar', 'baz']
Map<String, Object> result = strings.collectEntries { key ->
    [key, expensiveOperation(key)]
}

那么我的结果就像是

[foo: <an object>, bar: <another object>, baz: <another object>]

由于我需要做的操作很长并且不相互依赖,所以我一直愿意调查使用GPars并行运行循环。

但是,GPars有collectParallel方法并行循环收集并收集到List而不是收集到Map的collectEntriesParallel:正确的方法是什么这与GPars?

1 个答案:

答案 0 :(得分:2)

没有Private Sub dgv_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgvBlotter.CellValueChanged Dim r As Integer = e.RowIndex Dim c As Integer = e.ColumnIndex Try If r > -1 Then If c = 15 Then Dim flag As Double = dgv.CurrentRow.Cells("col2").Value 'name of comboboxcolumn Dim nuevovalor As Object = flag Dim nominal As Double = dgv.CurrentRow.Cells("col_3").Value dgv.CurrentRow.Cells("col_1").Value() = nuevovalor dgv.CurrentRow.Cells("col_2").Value() = (nuevovalor * nominal) End If End If Catch ex As Exception MsgBox("ERROR: " & ex.Message, MsgBoxStyle.Information) End Try End Sub ,因为它必须产生与:

相同的结果
collectEntriesParallel

Tim mentioned in the comment。除了将结果并行收集到列表并最终收集以顺序方式映射条目之外,很难以确定的方式制作要映射(或任何其他可变容器)的值的减少列表。请考虑以下顺序示例:

collectParallel {}.collectEntries {}

在这个例子中,我们使用的是Collection.inject(initialValue, closure),相当于好的旧&#34;向左折叠&#34; operation - 以初始值static def expensiveOperation(String key) { Thread.sleep(1000) return key.reverse() } List<String> strings = ['foo', 'bar', 'baz'] GParsPool.withPool { def result = strings.inject([:]) { seed, key -> println "[${Thread.currentThread().name}] (${System.currentTimeMillis()}) seed = ${seed}, key = ${key}" seed + [(key): expensiveOperation(key.toString())] } println result } 开始,迭代所有值,并将它们作为键和值添加到初始映射中。在这种情况下,顺序执行大约需要3秒钟(每[:]次休眠1秒钟)。

控制台输出:

expensiveOperation()

这基本上是[main] (1519925046610) seed = [:], key = foo [main] (1519925047773) seed = [foo:oof], key = bar [main] (1519925048774) seed = [foo:oof, bar:rab], key = baz [foo:oof, bar:rab, baz:zab] 所做的 - 它是一种减少操作,其中初始值是空地图。

现在让我们看看如果我们尝试将其并行化会发生什么 - 而不是collectEntries()我们会使用inject方法:

injectParallel

让我们看看结果是什么:

GParsPool.withPool {
    def result = strings.injectParallel([:]) { seed, key ->
        println "[${Thread.currentThread().name}] (${System.currentTimeMillis()}) seed = ${seed}, key = ${key}"
        seed + [(key): expensiveOperation(key.toString())]
    }

    println result
}

正如您所看到的[ForkJoinPool-1-worker-1] (1519925323803) seed = foo, key = bar [ForkJoinPool-1-worker-2] (1519925323811) seed = baz, key = [:] [ForkJoinPool-1-worker-1] (1519925324822) seed = foo[bar:rab], key = baz[[:]:]:[] foo[bar:rab][baz[[:]:]:[]:][:]:]:[[zab] 的并行版本并不关心订单(预期的订单),例如第一个帖子收到inject作为foo变量,seed作为关键字。如果对地图(或任何可变对象)的缩减是并行执行且没有特定顺序的话,就会发生这种情况。

解决方案

有两种方法可以并行化流程:

1。 bar + collectParallel组合

正如Tim Yates在评论中提到的那样,你可以将昂贵的操作执行并行,最后按顺序将结果收集到地图中:

collectEntries

此示例在大约1秒内执行并产生以下输出:

static def expensiveOperation(String key) {
    Thread.sleep(1000)
    return key.reverse()
}

List<String> strings = ['foo', 'bar', 'baz']

GParsPool.withPool {
    def result = strings.collectParallel { [it, expensiveOperation(it)] }.collectEntries { [(it[0]): it[1]] }

    println result
}

2。 Java的并行流

或者,您可以使用带有[foo:oof, bar:rab, baz:zab] 缩减函数的Java并行流:

Collectors.toMap()

此示例也在大约1秒内执行,并产生如下输出:

static def expensiveOperation(String key) {
    Thread.sleep(1000)
    return key.reverse()
}

List<String> strings = ['foo', 'bar', 'baz']

def result = strings.parallelStream()
        .collect(Collectors.toMap(Function.identity(), { str -> expensiveOperation(str)}))

println result 

希望它有所帮助。