이고르가 맞습니다. 단지 하나의 스레드가 모든 로그 기록을 수행하도록하십시오. 커널은 파일 위치를 추적하는 열린 파일 설명자에 대한 액세스를 동기화하기 위해 잠금을 수행해야하므로 여러 코어에서 쓰기를 수행하면 커널 내부에서 충돌이 발생합니다. 더 나쁜 것은 여러 개의 코어에서 시스템 호출을하는 것입니다. 즉, 커널의 코드/데이터 액세스가 여러 코어에서 캐시를 더럽힐 수 있습니다.
시스템 호출이 syscall이 완료된 후 사용자 공간 코드 성능에 미치는 영향에 대한 자세한 내용은 this paper을 참조하십시오. (드물게 syscalls에 대한 커널 내부의 데이터/명령 캐시 누락에 대해서). 하나의 스레드가 모든 시스템 호출을 처리하는 것, 적어도 모든 시스템 호출을 작성하는 것이 프로세스의 풋 프린트의 일부분을 하나의 코어로 분리하는 것입니다. 커널 내부의 잠금 경합뿐만 아니라
FlexSC 논문은 사용자 -> 커널 -> 사용자 전환을 줄이기위한 시스템 호출 일괄 처리에 대한 아이디어이지만 일반적인 동기 시스템 호출 방법의 오버 헤드도 측정합니다. 더 중요한 것은 시스템 호출로부터 캐시 오염에 대한 논의입니다.
다른 방법으로, 여러 스레드가 로그 파일에 쓸 수있게하면 그냥 대기열을 사용하지 않고 그대로 사용할 수 있습니다.
대용량 쓰기가 중단되지 않을 것이라고 보장 할 수는 없지만 중소 크기 쓰기는 대부분의 OS에서 항상 전체 버퍼를 복사해야합니다. 특히 파이프가 아니라 파일에 쓰는 경우 특히 그렇습니다. IDK는 Linux write()가 선매 (preempted) 될 때 어떻게 동작 하는지를 IDK가 알고 있지만 요청 된 바이트를 모두 쓰지 않고 리턴하지 않고 보통 쓰기를 끝내기를 기대한다. 부분 쓰기는 신호로 인해 중단 될 가능성이 더 높습니다.
두 개의 write()
시스템 호출의 바이트가 함께 혼합되지 않습니다. 한 바이트의 모든 바이트는 다른 바이트의 앞뒤에 있습니다. 그래도 부분 쓰기가 잠재적 인 문제라는 것은 맞습니다. glibc syscall wrapper가 EINTR
에 대한 호출을 다시 시작하는지 잊어 버립니다. 이 경우 실제로는 기록 된 바이트가 없거나 바이트 수로 성공을 리턴했을 것입니다.
부분 쓰기 및 성능을 테스트해야합니다. 커널 공간 잠금은 잠금없는 대기열의 오버 헤드보다 저렴할 수 있지만 로그 메시지를 생성하는 모든 스레드에서 시스템 호출을하면 성능이 저하 될 수 있습니다.(그리고 이것을 테스트 할 때 에만 전화 만 쓰는 것이 아니라 사용자 공간 프로세스에서 실제 작업을 수행해야합니다.
나는 본질을 잘 이해하고 있는지 잘 모르겠다. 문제. 당신이 누구와 경쟁하고 있다고 생각합니까? "상호"배제는 자원을 공유하려는 최소한 두 당사자의 존재를 전제로합니다 - 귀하가 우려하는이 두 번째 당사자는 누구입니까? –
스트리밍하기 위해 경쟁하는 두 개의 스레드가 있습니다. – Gilgamesz
글쎄, 하나의 스레드 만 실제로 I/O를 수행한다는 명백한 목적을위한 큐가있는이 정교한 설정이 있습니다. 그렇다면 왜 당신은 같은 파일에 쓰는 쓰레드를 더 많이 도입하여 자신의 디자인을 방해합니까? 대기열을 사용하는 데있어 중요한 점은 무엇입니까? 그러면 파일을 쓸 수있는 모든 것을 자유롭게 쓸 수 있다면 어떨까요? –