比较2个数据集可能与并发/异步/并行方法

Use*_*d82 11 comparison performance cpu-cores perl6 raku

我目前正在尝试改进现有的机制(比较来自2个源的数据,在perl5中实现),并且想要使用perl6.

在未压缩的平面文件中,我的目标数据量范围约为20-30 GB.就行而言,文件可以包含1800万到2800万行.它每行大约有40-50列.

我每天都会进行这种类型的数据协调,从文件中读取并填充哈希值大约需要10分钟.花了大约20分钟来读取这两个文件并填充哈希值.

比较过程大约需要30-50分钟,包括迭代哈希,收集所需的结果,以及写入输出文件(csv,psv).

总而言之,在具有256GB RAM(包括间歇性服务器负载)的32核双xeon cpu服务器上执行此过程可能需要30分钟到60分钟之间的任何时间.

现在我想进一步降低总处理时间.

这是我目前使用perl5的单线程方法.

  1. 从2个源(比如s1和s2)中逐个获取数据,并根据键值对填充哈希值.数据源可以是平坦的csv或psv文件,也可以是数据库查询Array of Array结果,通过DBI客户端.数据始终未分类.
  2. 具体来说,我逐行读取文件,拆分字段,并为键,值对选择所需的索引并插入哈希.
  3. 在收集数据并用所需的键/值对填充哈希之后,我开始比较并收集结果(主要比较s2和s1中缺少或不同的内容,反之亦然).
  4. 在excel文件中转储输出(如果没有大约100万或更大的行,则非常昂贵)或简单的CSV(廉价操作.首选方法).

我想知道我是否可以以某种方式并行执行第一步,即同时从两个源收集数据并填充我的全局哈希,然后继续比较和转储输出?

perl6可以提供哪些选项来处理这种情况?我已经阅读了有关使用perl6的并发,异步和并行操作,但我不确定哪一个可以帮助我.

我非常感谢有关此事的任何一般性指导.我希望我能很好地解释我的问题,但遗憾的是我没有太多东西可以证明我到现在为止做了什么?原因是我刚刚开始解决这个问题.我只是无法看到过去的单线程方法,需要一些帮助.

谢谢.

编辑

由于我现有的问题陈述被社区视为"过于宽泛" - 请允许我尝试突出以下的难点:

  1. 如果可能的话,我想利用所有32个内核进行文件比较.我只是无法提出策略或初步想法.
  2. 为了解决这个问题或问题类型,perl6可以使用或适用哪种新技术.
  3. 如果我产生2个进程来读取文件并收集数据 - 是否可以将结果作为数组或哈希返回?
  4. 是否可以并行比较数据(存储在哈希中)?

我目前的p5比较逻辑如下所示,供您参考.希望这有帮助,不要让这个问题关闭.

package COMP;

use strict;
use Data::Dumper;


sub comp 
{
  my ($data,$src,$tgt) = @_; 
  my $result = {};

  my $ms    = ($result->{ms} = {});
  my $mt    = ($result->{mt} = {});
  my $diff  = ($result->{diff} = {});

  foreach my $key (keys %{$data->{$src}})
  {
    my $src_val = $data->{$src}{$key};
    my $tgt_val = $data->{$tgt}{$key};

    next if ($src_val eq $tgt_val);

    if (!exists $data->{$tgt}{$key}) {
      push (@{$mt->{$key}}, "$src_val|NULL");
    }
    if (exists $data->{$tgt}{$key} && $src_val ne $tgt_val) {
      push (@{$diff->{$key}}, "$src_val|$tgt_val") 
    }
  }

  foreach my $key (keys %{$data->{$tgt}})
  {
    my $src_val = $data->{$src}{$key};
    my $tgt_val = $data->{$tgt}{$key};

    next if ($src_val eq $tgt_val);

    if (!exists $data->{$src}{$key}) {
      push (@{$ms->{$key}},"NULL|$tgt_val");
    }
  } 

  return $result;
}

1;
Run Code Online (Sandbox Code Playgroud)

如果有人想尝试一下,这里是示例输出和使用的测试脚本.

脚本输出

[User@Host:]$ perl testCOMP.pl 
$VAR1 = {
          'mt' => {
                    'Source' => [
                                  'source|NULL'
                                ]
                  },
          'ms' => {
                    'Target' => [
                                  'NULL|target'
                                ]
                  },
          'diff' => {
                      'Sunday_isit' => [
                                         'Yes|No'
                                       ]
                    }
        };
Run Code Online (Sandbox Code Playgroud)

测试脚本

[User@Host:]$  cat testCOMP.pl 
#!/usr/bin/env perl

use lib $ENV{PWD};
use COMP;
use strict;
use warnings;
use Data::Dumper;

my $data2 = {
  f1 => {
    Amitabh => 'Bacchan',
    YellowSun => 'Yes', 
    Sunday_isit => 'Yes',
    Source => 'source',
  },
  f2 => {
    Amitabh => 'Bacchan',
    YellowSun => 'Yes', 
    Sunday_isit => 'No',
    Target => 'target',
  },
};

my $result = COMP::comp ($data2,'f1','f2');
print Dumper $result;
[User@Host:]$ 
Run Code Online (Sandbox Code Playgroud)

Hol*_*lli 1

如果您有现有且可用的工具链,则无需全部重写即可使用 Perl6。它的并行机制也适用于外部进程。考虑

allnum.pl6

use v6;

my @processes = 
    [ "num1.txt", "num2.txt", "num3.txt", "num4.txt", "num5.txt" ]
        .map( -> $filename {
            [ $filename, run "perl", "num.pl", $filename, :out ];
        })
        .hyper;

say "Lazyness Here!";
my $time = time;
for @processes
{
    say "<{$_[0]} : {$_[1].out.slurp}>";
}
say time - $time, "s";
Run Code Online (Sandbox Code Playgroud)

数字.pl

use warnings;
use strict;

my $file = shift @ARGV;
my $start = time;
my $result = 0;

open my $in, "<", $file or die $!;
while (my $thing = <$in>)
{
    chomp $thing;
    $thing =~ s/ //g;
    $result = ($result + $thing) / 2;
}
print $result, " : ", time - $start, "s";
Run Code Online (Sandbox Code Playgroud)

在我的系统上

C:\Users\holli\tmp>perl6 allnum.pl6
Lazyness Here!
<num1.txt : 7684.16347578616 : 3s>
<num2.txt : 3307.36261498186 : 7s>
<num3.txt : 5834.32817942962 : 10s>
<num4.txt : 6575.55944995197 : 0s>
<num5.txt : 6157.63100049619 : 0s>
10s
Run Code Online (Sandbox Code Playgroud)

文件是这样设置的

C:\Users\holli\tmp>perl -e "for($i=0;$i<10000000;$i++) { print chr(32) ** 100, int(rand(1000)), chr(32) ** 100, qq(\n); }">num1.txt
C:\Users\holli\tmp>perl -e "for($i=0;$i<20000000;$i++) { print chr(32) ** 100, int(rand(1000)), chr(32) ** 100, qq(\n); }">num2.txt
C:\Users\holli\tmp>perl -e "for($i=0;$i<30000000;$i++) { print chr(32) ** 100, int(rand(1000)), chr(32) ** 100, qq(\n); }">num3.txt
C:\Users\holli\tmp>perl -e "for($i=0;$i<400000;$i++) { print chr(32) ** 100, int(rand(1000)), chr(32) ** 100, qq(\n); }">num4.txt
C:\Users\holli\tmp>perl -e "for($i=0;$i<5000;$i++) { print chr(32) ** 100, int(rand(1000)), chr(32) ** 100, qq(\n); }">num5.txt
Run Code Online (Sandbox Code Playgroud)