출력을 / dev / null로 리디렉션하더라도 printf에 여전히 비용이 발생합니까?
많은 인쇄 메시지를 포함하는 데몬이 있습니다. CPU 및 기타 제약 하드웨어가 약한 임베디드 장치에서 작업하고 있기 때문에 최종 버전에서 printf 메시지의 모든 종류의 비용 (IO, CPU 등)을 최소화하려고합니다. (사용자에게는 콘솔이 없습니다)
내 팀원과 나는 의견이 일치하지 않습니다. 그는 우리가 모든 것을 / dev / null로 리디렉션 할 수 있다고 생각합니다. IO 비용이 들지 않으므로 애정이 최소화됩니다. 하지만 여전히 CPU 비용이들 것이며 printf에 대한 매크로를 정의하는 것이 더 낫기 때문에 "printf"를 다시 작성할 수 있습니다 (아마도 그냥 돌아올 수도 있습니다).
그래서 누가 옳은지에 대한 의견이 필요합니다. Linux가 printf를 최적화 할만큼 똑똑할까요? 나는 그것을 정말로 의심한다.
꽤 많이.
프로그램의 stdout을로 리디렉션하면에 대한 /dev/null
모든 호출 printf(3)
은 여전히 모든 인수를 평가하고 문자열 형식 지정 프로세스는를 호출하기 전에 계속 발생 write(2)
하여 전체 형식화 된 문자열을 프로세스의 표준 출력에 기록합니다. 데이터가 디스크에 기록되지 않고 특수 장치와 관련된 핸들러에 의해 폐기되는 것은 커널 수준입니다 /dev/null
.
따라서 최선을 다하면 인수를 평가하고 인수를 전달하는 오버 헤드 printf
, 뒤에있는 문자열 형식 지정 작업 printf
및 stdout을로 리디렉션하여 실제로 데이터를 쓰는 시스템 호출을 하나 이상 우회하거나 회피하지 않습니다 /dev/null
. 글쎄, 그것은 Linux에서 진정한 차이입니다. 구현은 작성하려는 바이트 수를 반환하고 (호출의 세 번째 인수로 지정됨 write(2)
) 나머지는 모두 무시합니다 ( 이 답변 참조 ). 쓰고있는 데이터의 양과 대상 장치 (디스크 또는 터미널)의 속도에 따라 성능 차이가 크게 달라질 수 있습니다. 일반적으로 임베디드 시스템에서는 다음으로 리디렉션하여 디스크 쓰기를 차단합니다./dev/null
적은 양의 기록 된 데이터에 대해 상당량의 시스템 리소스를 절약 할 수 있습니다.
이론적으로 프로그램 /dev/null
은 일반적인 구현에 대한 일반적인 이해를 기반으로 준수하는 표준 (ISO C 및 POSIX)의 제한 내에서 일부 최적화를 감지 하고 수행 할 수 있지만 실제로는 그렇지 않습니다 (즉, Unix 또는 Linux를 알지 못합니다. 시스템).
POSIX 표준은에 대한 모든 호출에 대해 표준 출력에 쓰기를 요구 printf(3)
하므로 write(2)
관련 파일 설명자에 따라 호출을 억제하는 것은 표준을 준수하지 않습니다 . POSIX 요구 사항에 대한 자세한 내용은 Damon의 답변을 참조하십시오 . 아, 그리고 빠른 메모 : 모든 Linux 배포판은 인증 되지 않았음에도 불구하고 사실상 POSIX와 호환 됩니다.
printf
완전히 교체하면 예를 들어 일부 부작용이 잘못 될 수 있습니다 printf("%d%n", a++, &b)
. 프로그램 실행 환경에 따라 출력을 억제해야하는 경우 전역 플래그를 설정하고 printf를 래핑하여 인쇄하기 전에 플래그를 확인하는 것이 좋습니다. 성능 손실이 눈에 보일 정도로 프로그램 속도가 느려지지는 않습니다. , 단일 조건 검사가 모든 문자열 형식화를 호출 하고 수행하는 것보다 훨씬 빠릅니다 printf
.
printf
기능을 합니다 쓰기 stdout
. 에 대한 최적화를 준수하지 않습니다 /dev/null
. 따라서 형식 문자열을 구문 분석하고 필요한 인수를 평가하는 오버 헤드를 갖게되며 최소한 하나의 syscall을 갖게 될 것이며 커널 주소 공간에 버퍼를 복사 할 것입니다 (syscall 비용에 비해 무시할 수 있음). .
이 답변은 POSIX의 특정 문서를 기반으로합니다.
시스템 인터페이스
dprintf, fprintf, printf, snprintf, sprintf-인쇄 형식 출력fprintf () 함수는 이름 지정된 출력 스트림에 출력을 배치합니다. printf () 함수는 표준 출력 스트림 stdout에 출력을 배치합니다. sprintf () 함수는 * s에서 시작하는 연속 바이트에 널 바이트 '\ 0'이 뒤에 오는 출력을 배치합니다. 충분한 공간을 사용할 수 있는지 확인하는 것은 사용자의 책임입니다.
기본 정의
는
POSIX.1-2017을 준수하는 구현의 경우 필수 기능 또는 동작을 설명해야합니다. 응용 프로그램은 기능 또는 동작의 존재에 의존 할 수 있습니다.
이 printf
함수는 stdout
. 연결된 파일 설명자가 stdout
로 리디렉션되면 /dev/null
출력은 어디에도 기록되지 않지만 (하지만 여전히 기록됩니다) printf
자체 호출 과 포맷은 계속 발생합니다.
printf () 소스를 지침으로 사용하여 printf ()를 래핑하고 noprint 플래그가 설정되면 즉시 반환하는 직접 작성하십시오. 이것의 단점은 실제로 인쇄 할 때 형식 문자열을 두 번 구문 분석해야하기 때문에 더 많은 리소스를 소비한다는 것입니다. 그러나 인쇄하지 않을 때는 무시할 수있는 리소스를 사용합니다. printf () 내부의 기본 호출이 최신 버전의 stdio 라이브러리로 변경 될 수 있으므로 단순히 printf ()를 대체 할 수 없습니다.
void printf2 (const char * formatstring, ...);
일반적으로 구현은 프로그램의 관찰 가능한 (기능적) 출력에 영향을주지 않는 경우 이러한 최적화를 수행 할 수 있습니다. 의 경우 printf()
프로그램이 반환 값을 사용하지 않고 %n
변환 이 없으면 구현이 아무 작업도 수행 할 수 없음을 의미합니다.
실제로 저는 현재 (2019 년 초) 이러한 최적화를 수행하는 Linux 구현을 알지 못합니다. 익숙한 컴파일러와 라이브러리가 출력 형식을 지정하고 커널에 의존하여 결과를 null 장치에 기록합니다. '무시합니다.
출력이 사용되지 않을 때 형식화 비용을 정말로 절약해야하는 경우 고유 한 전달 함수를 작성하고 싶을 수 있습니다. 출력을 반환하고 싶을 void
것이고 형식 문자열을 확인해야합니다 %n
. ( 이러한 부작용이 필요한 경우 snprintf
a NULL
및 0
buffer 와 함께 사용할 수 있지만, 투자 한 노력을 절약 할 수는 없습니다.)
'IT Share you' 카테고리의 다른 글
RxJava API와 Java 9 Flow API의 차이점 (0) | 2020.12.04 |
---|---|
신속하게 새 라인을 만드는 방법 (0) | 2020.12.03 |
int를 String으로 변환하는 가장 효율적인 방법은 무엇입니까? (0) | 2020.12.03 |
net.pipe 대 net.tcp 대 http 바인딩 (0) | 2020.12.03 |
onClick (DialogInterface v, int buttonId) 내에서 컨텍스트를 얻습니까? (0) | 2020.12.03 |