0

나는 boost :: asio를 사용하여 HTTP 서버를 작성하고있다. 대용량 파일의 경우 전체 파일을 메모리로 읽어 들이지 않고 네트워크로 보내는 것을 피하기 위해 boost :: asio :: async_write를 사용하여 네트워크에서 보내는 부분별로 읽습니다.boost :: async_write 대용량 파일 및 메모리 사용량

문제는 제작자 (파일에서 읽는 함수)가 소비자 (boost :: asio :: async_write)보다 훨씬 빠르기 때문에 큰 파일에 대해 막대한 메모리를 소비한다는 것입니다.

버퍼 목록을 제한하여이 문제를 방지하고 싶습니다. 그것은 단순한 생산자/소비자 문제처럼 보이지만 그렇게하는 동안 스레드를 차단하고 싶지는 않습니다.

구성 가능한 n 스레드의 스레드 풀과 함께 boost :: io_service를 사용합니다. 대용량 파일에 대해 너무 많은 요청이있는 경우 더 이상 요청을 처리하지 않는 서버로 끝내고 싶지 않습니다.

내 질문은 : - 스레드를 차단하지 않고이 메커니즘을 어떻게 디자인 할 수 있습니까? - 목록 크기를 테스트해야하고 이미 너무 큰 경우 io_service :: post를 수행하고 내 파일을 계속 읽는 마감 타이머를 생성 하시겠습니까? - 더 나은 방법이 있습니까?

+0

음. async_write를 통해 N 바이트를 전송한다고 가정합니다. async_write를 시작하고 동시에 파일에서 다음 N 바이트를 읽습니다 (2 작업 게시). 그런 다음 async_write가 끝나면 같은 작업을 반복하십시오. 따라서 아직 보내지 않은 파일 파트는 메모리에 보관하지 않습니다. –

답변

0

읽기 스레드를 차단하는 것은 좋은 생각이 아닙니다. DOS 공격을 막으려는 경우입니다. 당신이 피하려고하는 것은 너무 많은 양의 자원 (메모리)을 동시에 할당하는 것입니다. 그러나 열린 파일 스트림의 양은 제한되어 있습니다. 과부하 상황에서 읽기 스레드를 차단하기 시작하면 열려있는 파일 스트림이 매우 빠르게 증가 할 수 있습니다. 오류가 발생하면 프로그램이 중단되지는 않지만 다른 파일 (예 : 로그 파일)을 열 수 없으므로 바람직하지 않은 동작입니다.

이 문제를 방지하려면 두 리소스를 모두 고려해야합니다. 할당 된 리소스의 양을 제한하는 많은 알고리즘이 있습니다. 메모리의 경우 읽기 데이터 청크에 링 버퍼를 사용할 수 있습니다. 원자 카운터를 사용하여 할당 된 리소스의 양을 추적하고 상한을 설정할 수도 있습니다. 세마포어는 또한 이런 종류의 문제를 해결하는 데 사용될 수 있습니다. 나는 마지막 것을 더 좋아할 것이다. 의사 코드는 다음과 같습니다.

Semaphore filestreams(maxNumberOfFilestreams); 
Semaphore memory(maxNumberOfAllocatedChunks); 

// Worker thread to read 
void run() { 
    filestream.wait(); 
    while(!eof) { 
     memory.wait(); 
     // Allocate and read 
    } 
    file.close(); 
    filestream.notify() 
} 

// Sending thread() 

void run() { 
    while(true) { 
     // grab chunk, send and free memory 
     memory.notify(); 
    } 
} 

개방형 TCP 연결은 제한된 리소스이기도합니다.