当前位置: 首页 > 知识库问答 >
问题:

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

公西毅
2023-03-14

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

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

我每天进行这种类型的数据对帐,从文件读取并填充哈希值可能需要大约10分钟。大约花费 20 分钟来读取这两个文件并填充哈希。

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

总的来说,在一台32核双核至强cpu、256gb内存的服务器上,包括间歇性的服务器负载,执行该过程可能需要30分钟到60分钟。

现在我正试图进一步减少总处理时间。

下面是我当前使用perl5的单线程方法。

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

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

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

我真的很感激关于这个问题的任何一般指导。我希望我能很好地解释我的问题,但遗憾的是,到目前为止,我没有太多可以展示的东西?原因是我刚刚开始解决这个问题。我只是无法超越单线程方法,需要一些帮助。

谢谢。

编辑

由于我现有的问题陈述被社区认为“过于宽泛”——请允许我在下面强调我的痛点:

    < li >如果可能,我想利用所有32个内核进行文件比较。我就是想不出一个策略或最初的想法。 < li >为了解决这个问题或这类问题,perl6有哪些新技术可用或适用? < li >如果我生成2个进程来读取文件和收集数据,是否可能以数组或散列的形式返回结果? < li >可以并行比较数据(存储在哈希中)吗?

我目前的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;

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

脚本输出

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

测试脚本

[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:]$ 

共有1个答案

万俟招
2023-03-14

如果你有一个现有的和工作的工具链,你不必重写它来使用Perl6。它的并行机制在外部进程中也能很好地工作。考虑

全部

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";

编号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";

在我的系统

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

文件是这样设置的

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
 类似资料:
  • 问题内容: 我想知道如何比较两个布尔数组并列出不匹配的布尔值。 我写了一个2数组的简单示例。 我如何比较array1和array2并显示不匹配的内容。我正在尝试执行此操作以检查问答游戏的用户结果。 谢谢! 问题答案: 这里的 一个 实现,但无论是一个你追求的是完全不可能说,因为你没有指定你认为答案 应该 是: 如果答案与正确答案相匹配,则将为您提供布尔值列表。 但是,假设您想要的是正确答案的 索引

  • 我想我可以做一个逐行和逐列的比较,但有没有更简单的方法?

  • 有2个LinkedHashMaps。我必须检查两个LinkedHashMaps是否有相同的密钥。 例如 Map1包含{A-A、B-B、C-C} 地图 2 包含 {A-a, B-r, C-c, Z-z} 所以这里的第三个LinkedHashMap应该包含{Z-z},因为它包含额外的键和 {B-r}应该在修改时打印出来

  • 问题内容: 我有2个数据框,如下所示: 最后,我想得到的是: 因此,我想比较两个数据帧,我想查看第一数据帧(对于列A和B)的哪些行与第二数据帧(列K和L)相同,并在第一数据帧的列D上分配1。 我可以使用for循环,但是输入大量条目会很慢。 任何线索或建议将不胜感激。 问题答案: 这是我解决的方法:

  • 我有两个数据帧。示例: 每个数据帧都有日期作为索引。两个数据帧具有相同的结构。 我想做的是比较这两个数据帧,找出df2中哪些行不在df1中。我想比较日期(索引)和第一列(香蕉、苹果等),看看它们是否存在于df2和df1中。 我尝试了以下方法: 两个熊猫数据帧并排输出差异-突出差异 比较两个熊猫数据帧的差异 对于第一种方法,我得到这个错误:"异常:只能比较相同标记的DataFrame对象"。我尝试删

  • 谁能解释一下为什么下面的代码不起作用: 但这一个有效: 换句话说,与创建普通类实例相比,接口实现何时是可互换的?当我使用compareTo()方法时会出现错误,该方法是Comparable接口的一部分,由所有包装类(如整数)实现。 所以我猜