AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 500676
Accepted
katosh
katosh
Asked: 2019-02-15 10:19:09 +0800 CST2019-02-15 10:19:09 +0800 CST 2019-02-15 10:19:09 +0800 CST

使用大过滤器过滤大文件

  • 772

我想提取所有$file1以存储在$file2.

$file1大小为 4 GB,约有 2000 万行,$file2有 200 万行,大小约为 140 MB,包含两列,用,. 这两个文件的最大行长度远低于 1000,它们按顺序排序,LC_ALL=C并且$file1可以包含除\0.

没想到这个命令

parallel --pipepart -a $file1 grep -Ff $file2

消耗大量内存并被操作系统杀死。

如果我限制线程数,该命令有效:

parallel --pipepart -j 8 -a $file1 grep -Ff $file2

对于最后一个命令,htop 显示每个grep -Ff $file2-thread 始终占用 12.3 GB 的内存。我假设这个需求来自字典 grep 构建于$file2.

我怎样才能更有效地实现这样的过滤器?

shell-script text-processing
  • 1 1 个回答
  • 1355 Views

1 个回答

  • Voted
  1. Best Answer
    Ole Tange
    2019-02-16T08:17:02+08:002019-02-16T08:17:02+08:00

    它包含在man parallel https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Grepping-n-lines-for-m-regular-expressions

    示例:为 m 个正则表达式提取 n 行。

    为大量正则表达式 grep 大文件的最简单解决方案是:

    grep -f regexps.txt bigfile
    

    或者,如果正则表达式是固定字符串:

    grep -F -f regexps.txt bigfile
    

    有 3 个限制因素:CPU、RAM 和磁盘 I/O。

    RAM 易于测量:如果 grep 进程占用了您的大部分空闲内存(例如,在运行 top 时),那么 RAM 是一个限制因素。

    CPU 也很容易测量:如果 grep 占用 >90% 的 CPU,那么 CPU 是一个限制因素,并行化会加快速度。

    很难看出磁盘 I/O 是否是限制因素,并且取决于磁盘系统,并行化可能更快或更慢。唯一确定的方法是测试和测量。

    限制因素:RAM

    普通的 grep -f regexs.txt 大文件不管大文件的大小都可以工作,但是如果 regexps.txt 太大而无法放入内存,那么您需要将其拆分。

    grep -F 占用大约 100 字节的 RAM,而 grep 每 1 个字节的正则表达式占用大约 500 字节的 RAM。所以如果 regexps.txt 是你 RAM 的 1%,那么它可能太大了。

    如果您可以将您的正则表达式转换为固定字符串,请执行此操作。例如,如果您在 bigfile 中查找的所有行看起来都像:

    ID1 foo bar baz Identifier1 quux
    fubar ID2 foo bar baz Identifier2
    

    那么您的 regexps.txt 可以从以下位置转换:

    ID1.*Identifier1   
    ID2.*Identifier2
    

    进入:

    ID1 foo bar baz Identifier1
    ID2 foo bar baz Identifier2
    

    通过这种方式,您可以使用 grep -F 减少大约 80% 的内存并且速度更快。

    如果它仍然不适合内存,你可以这样做:

    parallel --pipepart -a regexps.txt --block 1M grep -Ff - -n bigfile |
      sort -un | perl -pe 's/^\d+://'
    

    1M 应该是您的可用内存除以 CPU 线程数,然后除以 200(grep -F)和 1000(普通 grep)。在 GNU/Linux 上,您可以:

    free=$(awk '/^((Swap)?Cached|MemFree|Buffers):/ { sum += $2 }
              END { print sum }' /proc/meminfo)
    percpu=$((free / 200 / $(parallel --number-of-threads)))k
    
    parallel --pipepart -a regexps.txt --block $percpu --compress \
      grep -F -f - -n bigfile |
      sort -un | perl -pe 's/^\d+://'
    

    如果您可以忍受重复的行和错误的顺序,那么这样做会更快:

    parallel --pipepart -a regexps.txt --block $percpu --compress \
      grep -F -f - bigfile
    

    限制因素:CPU

    如果 CPU 是限制因素,则应在正则表达式上进行并行化:

    cat regexp.txt | parallel --pipe -L1000 --round-robin --compress \
      grep -f - -n bigfile |
      sort -un | perl -pe 's/^\d+://'
    

    该命令将为每个 CPU 启动一个 grep 并为每个 CPU 读取一次大文件,但由于这是并行完成的,除第一个之外的所有读取都将缓存在 RAM 中。根据 regexp.txt 的大小,使用 --block 10m 而不是 -L1000 可能更快。

    一些存储系统在并行读取多个块时性能更好。这适用于某些 RAID 系统和某些网络文件系统。并行读取大文件:

    parallel --pipepart --block 100M -a bigfile -k --compress \
      grep -f regexp.txt
    

    这会将大文件拆分为 100MB 的块并在每个块上运行 grep。要并行读取 bigfile 和 regexp.txt,请使用 --fifo 将两者结合起来:

    parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \
      \| parallel --pipe -L1000 --round-robin grep -f - {}
    

    如果一行匹配多个正则表达式,则该行可能重复。

    更大的问题

    如果问题太大而无法通过此方法解决,那么您可能已经为 Lucene 做好了准备。

    • 4

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • 多行文件洗牌

  • MySQL Select with function IN () with bash array

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve