프로그래밍 언어/Python

Python보다 C ++에서 stdin에서 행을 읽는 것이 훨씬 느린 이유

Rateye 2021. 10. 26. 10:39
728x90
반응형
질문 : Python보다 C ++에서 stdin에서 행을 읽는 것이 훨씬 느린 이유는 무엇입니까?

Python과 C ++를 사용하여 stdin의 문자열 입력 행을 비교하고 싶었고 C ++ 코드가 동등한 Python 코드보다 훨씬 느리게 실행되는 것을보고 충격을 받았습니다. 내 C ++가 녹슬고 아직 Pythonista 전문가가 아니기 때문에 내가 뭘 잘못하고 있는지 또는 뭔가를 오해하고 있는지 알려주세요.

(TLDR 답변 : cin.sync_with_stdio(false) 문을 포함하거나 fgets 사용하십시오.

TLDR 결과 : 내 질문의 맨 아래로 스크롤하여 표를보십시오.)

C ++ 코드 :

#include <iostream>
#include <time.h>

using namespace std;

int main() {
    string input_line;
    long line_count = 0;
    time_t start = time(NULL);
    int sec;
    int lps;

    while (cin) {
        getline(cin, input_line);
        if (!cin.eof())
            line_count++;
    };

    sec = (int) time(NULL) - start;
    cerr << "Read " << line_count << " lines in " << sec << " seconds.";
    if (sec > 0) {
        lps = line_count / sec;
        cerr << " LPS: " << lps << endl;
    } else
        cerr << endl;
    return 0;
}

// Compiled with:
// g++ -O3 -o readline_test_cpp foo.cpp

동등한 Python :

#!/usr/bin/env python
import time
import sys

count = 0
start = time.time()

for line in  sys.stdin:
    count += 1

delta_sec = int(time.time() - start_time)
if delta_sec >= 0:
    lines_per_sec = int(round(count/delta_sec))
    print("Read {0} lines in {1} seconds. LPS: {2}".format(count, delta_sec,
       lines_per_sec))

내 결과는 다음과 같습니다.

$ cat test_lines | ./readline_test_cpp
Read 5570000 lines in 9 seconds. LPS: 618889

$ cat test_lines | ./readline_test.py
Read 5570000 lines in 1 seconds. LPS: 5570000

Mac OS X v10.6.8 (Snow Leopard)과 Linux 2.6.32 (Red Hat Linux 6.2) 모두에서 시도했습니다. 전자는 맥북 프로이고 후자는 너무 무거워서 너무 적절하지는 않다.

$ for i in {1..5}; do echo "Test run $i at `date`"; echo -n "CPP:"; cat test_lines | ./readline_test_cpp ; echo -n "Python:"; cat test_lines | ./readline_test.py ; done
Test run 1 at Mon Feb 20 21:29:28 EST 2012
CPP:   Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 2 at Mon Feb 20 21:29:39 EST 2012
CPP:   Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 3 at Mon Feb 20 21:29:50 EST 2012
CPP:   Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 4 at Mon Feb 20 21:30:01 EST 2012
CPP:   Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 5 at Mon Feb 20 21:30:11 EST 2012
CPP:   Read 5570001 lines in 10 seconds. LPS: 557000
Python:Read 5570000 lines in  1 seconds. LPS: 5570000

작은 벤치 마크 부록 및 요약

완전성을 위해 원래 (동기화 된) C ++ 코드로 동일한 상자에있는 동일한 파일의 읽기 속도를 업데이트 할 것이라고 생각했습니다. 다시 말하지만 이것은 빠른 디스크에있는 100M 라인 파일 용입니다. 다음은 몇 가지 솔루션 / 접근법과의 비교입니다.

답변

기본적으로 cin 은 stdio와 동기화되어 입력 버퍼링을 방지합니다. 이것을 메인 상단에 추가하면 훨씬 더 나은 성능을 볼 수 있습니다.

std::ios_base::sync_with_stdio(false);

일반적으로 입력 스트림이 버퍼링되면 한 번에 한 문자를 읽는 대신 스트림을 더 큰 청크로 읽습니다. 이는 일반적으로 상대적으로 비용이 많이 드는 시스템 호출 수를 줄입니다. 그러나 FILE* 기반 stdioiostreams 종종 별도의 구현이 있으므로 별도의 버퍼가 있기 때문에 둘 다 함께 사용하면 문제가 발생할 수 있습니다. 예를 들면 :

int myvalue1;
cin >> myvalue1;
int myvalue2;
scanf("%d",&myvalue2);

cin 이 실제로 필요한 것보다 더 많은 입력을 읽은 경우 두 번째 정수 값은 자체 독립 버퍼가 scanf 이로 인해 예기치 않은 결과가 발생할 수 있습니다.

이를 방지하기 위해 기본적으로 스트림은 stdio 와 동기화됩니다. 이를 달성하는 한 가지 일반적인 방법은 stdio cin 각 문자를 한 번에 하나씩 읽도록하는 것입니다. 불행히도 이로 인해 많은 오버 헤드가 발생합니다. 적은 양의 입력의 경우 큰 문제는 아니지만 수백만 줄을 읽는 경우 성능 저하가 상당합니다.

다행히도 라이브러리 디자이너는 수행중인 작업을 알고있는 경우 성능을 향상시키기 위해이 기능을 비활성화 할 수 있어야한다고 결정하여 sync_with_stdio 메서드를 제공했습니다.

출처 : https://stackoverflow.com/questions/9371238/why-is-reading-lines-from-stdin-much-slower-in-c-than-python
728x90
반응형