使用Ruby并使用Parallel和JRuby 1.7.19编写以下代码,以加速从具有多个值的数组创建哈希:
hash = {}
array = [
{"id" => "A001", "value" => 1},
{"id" => "B002", "value" => 0},
{"id" => "C003", "value" => 3},
{"id" => "D004", "value" => 0}]
Parallel.each(array, { in_threads: 5 }) do |item|
if keep_item?(item)
hash[item["id"]] = item
end
end
def keep_item?(item)
item["value"] > 0
end
我注意到在Ruby中并行添加哈希值的问题可能存在问题。这段代码是否存在任何风险(线程安全,数据丢失,我不知道的奇怪锁等),我应该把它作为常规系列#each
调用?
答案 0 :(得分:3)
Hash
不是线程安全的。如果keep_item?
访问hash
,则会出现竞争状况。即使它没有,也会有hash
的并发更新,这很容易出错。
如果没有锁定或其他同步,理论上不能保证在一个线程上对非线程安全hash
的更新在其他线程上可见。没有同步的hash
的并发更新可能会丢失数据,或导致其他奇怪的问题。这取决于Ruby Hash
的实现。
您的数据很简单,只需使用普通each
处理它们即可。如果使用Parallel
并添加mutex/lock
以进行线程安全访问,则同步开销将显着增加整个进程的额外时间成本。安全并行版本可能会占用更多时间。
Parallel
在您的任务为IO
限制时非常有用,或者只要您拥有可用内核并且任务不需要在彼此之间交换数据,CPU就会受到限制。
答案 1 :(得分:1)
虽然Arie Shaw对Hash不是线程安全是正确的,但我认为你的实现比任何事情更重要。如果您必须并行处理,我建议使用ndx = crossfilter(data);
dataTable = dc.dataTable('#data-table');
var tableDim = ndx.dimension(function(d) {
return d.gender + "/" + d.hair-color + "/" + d.pets;
});
dataTable
.width(400)
.height(800)
.dimension(tableDim)
.group(function(d){
return "Data Counts";
}),
.columns([
function(d) {
return d.gender;
},
function(d) {
return d.hair-color;
},
function(d) {
return d.pets;
}
function(d) {
if (d.group == 1) return d.totals;
else return 0;
},
function(d) {
if (d.group == 2) return d.totals;
else return 0;
},
function(d) {
if (d.group == 3) return d.totals;
else return 0;
代替。
Parallel::map
请注意,这比直接在阵列上运行它要慢得多,例如。
#lambda just to create the array structure
lam = ->(n) {n.times.map {|i| {'id' => 'A' + i.to_s, 'value' => [i,0].shuffle.pop }}}
a = lam.call(40_000)
require 'parallel'
Parallel.map(a,in_threads: 5) {|h| [h['id'],h] if h['value'] > 0}.compact.to_h
a.map {|h| [h['id'],h] if h['value'] > 0}.compact.to_h
结果:
fruity