我需要迭代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?
答案 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
作为关键字。如果对地图(或任何可变对象)的缩减是并行执行且没有特定顺序的话,就会发生这种情况。
有两种方法可以并行化流程:
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
}
或者,您可以使用带有[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
希望它有所帮助。