![단어 주파수 gawk 메모리 누수](https://linux55.com/image/98490/%EB%8B%A8%EC%96%B4%20%EC%A3%BC%ED%8C%8C%EC%88%98%20gawk%20%EB%A9%94%EB%AA%A8%EB%A6%AC%20%EB%88%84%EC%88%98.png)
다음 bash 스크립트가 있습니다.
#!/usr/bin/env bash
grep -e '^[a-zA-Z]\{4,8\}$' data/words3.txt | tr '[:upper:]' '[:lower:]' | sort -u > data/passphrase-words.txt
function wordfrequency() {
awk '{ for (i=1; i<=NF; i++) { word = tolower($i); words[word]++ } } END { for (w in words) printf("%3d %s\n", words[w], w) } ' | sort -rn
}
function getArticleText() {
awk '/<text xml:space="preserve">/,/<\/text>/' | sed 's/<.*>//'
}
function reduceWikiText() {
tr ' [:punct:]' '[\n*]' | sed '/^$/d' | tr '[:upper:]' '[:lower:]'
}
bzcat data/enwiki-20161020-pages-articles.xml.bz2 | getArticleText | reduceWikiText | grep -F -f data/passphrase-words.txt | wordfrequency > data/wordFreqs.txt
여러 가지 방법으로 단순화할 수 있다고 확신하지만 이것이 제가 생각해낸 것입니다. data/passphrase-words는 한 줄에 한 단어씩 약 170,000개의 단어로 구성된 목록입니다. data/enwiki-*
12GB의 압축된 XML입니다(Wikipedia 덤프입니다). 여기에서 getArticleText는 각 기사의 텍스트를 가져오고, ReduceWikiText는 해당 텍스트를 한 줄에 한 단어로 "줄이고" 모든 XML과 구두점을 제거하는 반면, 단어 빈도는 각 단어가 나타나는 빈도를 계산합니다.
작업 관리자를 올바르게 읽으면 wordFrequency() 내부의 gawk가 695MB, 충분히 오래 실행하면 1GB 이상의 메모리를 사용하고 있습니다.
어떤 기능에도 속하지 않는 grep 명령은 gawk가 볼 수 있는 고유 단어 수를 제한하며 일정한 36MB를 차지합니다. 50MB 또는 100MB가 필요한 gawk를 볼 수 있지만 1GB 이상이면 어떻게 될까요? 이것은 잘못된 것 같습니다. 성장률은 무한정 성장한다는 의미입니다.
gawk가 왜 그렇게 많은 메모리를 사용하는지 알아내야 합니까? BZ2 파일의 크기로 인해 gawk가 너무 많이 손에서 벗어날 수는 없습니다...
내가 sort | uniq-c| sort -nr을 사용하지 않는 이유는 내가 작업 중인 단어 수에 대해 작동한다는 것을 알고 있기 때문입니다. HDD 사용량 감소 = 더 빠르죠?
참고로 Windows용 Linux 하위 시스템은 다음과 같습니다.
$ gawk --version
GNU Awk 4.0.1
Copyright (C) 1989, 1991-2012 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
편집하다:내가 얻은 것(12GB .xml.bz2 파일 제외)을 다음 위치에 게시합니다.https://github.com/proegssilb/wikipedia-wordcount. 댓글에서 제안한 대로 mawk를 사용해도 아무 일도 일어나지 않는 것 같았지만 200MB RAM에서 프로세스를 중지했습니다. 무슨 일이 일어나는지 확인하기 위해 awk를 사용하지 않고 밤새 프로세스를 실행해 보세요.
편집 2:문제가 있는 awk를 교체 한 후 | sort | uniq -c
제가 없는 동안 6~7시간 만에 작업이 완료되었습니다. 나는 몇 가지 추가 조정을 하고 기사에서 HTML 사용을 제거하고(너무 많은 오염을 일으키는 """ 제거) 다시 시간을 재려고 노력할 것입니다. 그러나 적어도 지금은 "합리적인" 환경에서 실행됩니다. " 시간.
답변1
따라서 도움이 되는 몇 가지 사항이 있지만 이 작업을 수행하는 데 가장 중요한 것은 sort | uniq -c
gawk 대신그레고리 니스벳(Gregory Nisbet)에 따르면.
나도 결국 사용하게 됐어@dave_thompson_085의 댓글에 대한 tr -sc '[:alpha:]' '\n'
. 이 플래그는 반복을 결합합니다. 즉, 빈 줄을 제거하고 찾고 있는 문자 집합을 반대로 바꿀 -s
필요가 없습니다 . -c
의 부작용은 -c
세트가 아닌 하나의 대체 문자만 사용할 수 있다는 것입니다. 데이브에게도 감사드립니다grep 및 정확한 라인 매칭에 대한 질문( -x
). 내가 이 댓글에 투표할 평판이 있었다면 그렇게 했을 것입니다.
결국 XML 엔터티( "
)를 제거하고 html(중복 <ref />
)을 제거하기 위해 몇 가지 추가 코드를 사용해야 했습니다. 에서 getArticleText
새로운 sed 명령은 입니다 | sed -e 's/"/"/g' -e 's/</</g' -e 's/>/>/g' -e 's/&/&/g' -e 's/<.*>//g'
. 각 표현식( -e
link 명령)은 서로 다른 HTML 엔터티를 처리합니다. 나는 좀 더 완전한 옵션을 시도했습니다(예: Perl 사용).스택 오버플로), 하지만 내 경우에는 컴퓨터 관련 문제로 인해 작동하지 않습니다. 최종 스크립트는 다음에서 찾을 수 있습니다.나의 단어 라이브러리.
내 컴퓨터에서 스크립트를 완료하는 데 3시간 20분이 걸렸지만 이 드라이브도 몇 년 전의 6코어 AMD 드라이브였습니다. 귀하의 마일리지는 다를 수 있지만 이것으로 충분했습니다.
@Gregory Nisbet 또는 @dave_thompson_085가 자신의 답변을 게시하려는 경우 게시할 수 있도록 이 답변을 수락하지 않겠습니다.