물리 시뮬레이션을 개발 중이며 프로그래밍에 익숙하지 않아서 큰 프로그램 (주로 메모리 문제)을 생성 할 때 계속 문제가 발생합니다. 동적 메모리 할당 및 삭제 (신규 / 삭제 등)에 대해 알고 있지만 프로그램을 구성하는 방법에 대한 더 나은 접근 방식이 필요합니다.
매우 빠른 샘플링 속도로 며칠 동안 실행되는 실험을 시뮬레이션한다고 가정 해 봅시다. 10 억 개의 샘플을 시뮬레이트하고 실행해야합니다.
단순화 된 버전으로서, 우리는 프로그램이 전압 V [i]를 취하고 5를 합산한다고 말합니다 :
즉 NewV [0] = V [0] + V [1] + V [2] + V [3] + V [4]
NewV [1] = V [1] + V [2] + V [3] + V [4] + V [5]
NewV [2] = V [2] + V [3] + V [4] + V [5] + V [6] … 이는 10 억 개의 샘플에 대해 계속됩니다.
결국, 나는 V [0], V [1], …, V [1000000000]을 가지게되는데, 대신 다음 단계를 위해 저장해야 할 유일한 것이 마지막 5V [i] 일 때 에스.
메모리를 다시 자유롭게 사용할 수 있도록 배열의 일부 를 삭제 / 할당 해제하려면 어떻게해야합니까 (예를 들어 더 이상 필요하지 않은 예제의 첫 부분 다음에 V [0])? 그러한 프로그램을 구성하는 방법에 대한 대안이 있습니까?
malloc / free에 대해 들었지만 C ++에서 사용해서는 안되며 더 나은 대안이 있다고 들었습니다.
매우 감사합니다!
tldr; 배열 (개별 요소)의 일부로 무엇을해야합니까? 더 많은 메모리를 차지하는 더 이상 필요하지 않습니까?
답변
“매끄럽게 5″로 설명하는 것은 유한 임펄스 응답 (FIR) 디지털 필터입니다. 이러한 필터는 순환 버퍼로 구현됩니다. 마지막 N 값만 유지하고, 가장 오래된 값이 어디에 있는지 알려주는 인덱스를 버퍼에 유지하고, 각 단계에서 가장 오래된 값으로 현재 가장 오래된 값을 겹쳐 쓰며 매번 인덱스를 단계별로 실행합니다.
수집 한 데이터를 크런치 할 디스크에 보관합니다.
환경에 따라 경험이 풍부한 도움을받는 것이 더 좋은 곳 중 하나 일 수 있습니다. 대학에서는 컴퓨터 과학 부서의 게시판에 메모를 작성하여 몇 시간 동안 작업 한 학생 임금 (또는 학생 상담 비율)을 제공하여 데이터를 처리하는 데 도움을줍니다. 또는 학부 연구 기회 포인트를 제공 할 수도 있습니다. 또는 뭔가.
답변
추가적인 수준의 간접 지시를 추가하여 모든 문제를 해결할 수 있습니다. 그렇게하세요.
C ++에서는 배열의 일부를 삭제할 수 없습니다. 그러나 유지하려는 데이터 만 보유한 새 배열을 만든 다음 이전 배열을 삭제할 수 있습니다. 따라서 원하지 않는 요소를 정면에서 “제거”할 수있는 데이터 구조를 구축 할 수 있습니다. 실제로 할 일은 새 배열을 만들고 제거되지 않은 요소를 새 배열로 복사 한 다음 이전 배열을 삭제하는 것입니다.
또는 std::deque
이미 사용할 수있는을 사용할 수 있습니다. deque
“양쪽 대기열”은 한 쪽 끝에서 요소를 삭제하고 다른 쪽 끝에서 요소를 추가하는 경우를위한 데이터 구조입니다.
답변
귀하가받은 FIR 및 SMA 답변은 귀하의 경우에 적합하지만보다 일반적인 접근 방식을 추진할 기회를 갖고 싶습니다.
여기에있는 것은 데이터 스트림 입니다. 모든 데이터를 한 번에 메모리에로드 해야하는 3 가지 큰 단계 (데이터 가져 오기, 계산, 출력 결과)로 프로그램을 구성하는 대신 파이프 라인 으로 구성 할 수 있습니다 .
파이프 라인은 스트림으로 시작하여 변환 한 후 싱크로 푸시합니다.
귀하의 경우 파이프 라인은 다음과 같습니다.
- 디스크에서 항목을 읽고 한 번에 하나씩 항목을 내 보냅니다.
- 한 번에 하나씩 항목을 받으십시오.받은 각 항목에 대해 마지막으로받은 5 개의 항목 (라운드 버퍼가 들어오는 위치)을 방출하십시오.
- 각 그룹마다 결과를 계산하기 위해 한 번에 5 개의 항목을받습니다.
- 결과를 받아 디스크에 씁니다.
C ++은 스트림보다는 반복자를 사용하는 경향이 있지만 정직한 스트림은 모델링하기가 쉽습니다 ( 스트림과 비슷한 범위에 대한 제안 이 있습니다).
template <typename T>
class Stream {
public:
virtual boost::optional<T> next() = 0;
virtual ~Stream() {}
};
class ReaderStream: public Stream<Item> {
public:
boost::optional<Item> next() override final;
private:
std::ifstream file;
};
class WindowStream: public Stream<Window> {
public:
boost::optional<Window> next() override final;
private:
Window window;
Stream<Item>& items;
};
class ResultStream: public Stream<Result> {
public:
boost::optional<Result> next() override final;
private:
Stream<Window>& windows;
};
파이프 라인은 다음과 같습니다.
ReaderStream itemStream("input.txt");
WindowStream windowStream(itemsStream, 5);
ResultStream resultStream(windowStream);
std::ofstream results("output.txt", std::ios::binary);
while (boost::optional<Result> result = resultStream.next()) {
results << *result << "\n";
}
스트림은 항상 적용 가능하지는 않지만 (데이터에 무작위로 액세스해야 할 때 작동하지는 않지만), 스트림이 매우 적습니다. 매우 적은 양의 메모리에서 작동하면 CPU 캐시에 모두 유지됩니다.
또 다른 참고 사항 : 문제가 “엄청나게 평행 한”것처럼 보입니다. 큰 파일을 청크로 분할 할 수 있습니다 (5의 창으로 처리하려면 각 경계에 4 개의 공통 요소가 있어야 함을 명심하십시오) 그런 다음 청크를 병렬로 처리하십시오.
CPU가 병목 현상 (I / O가 아님) 인 경우 파일을 대략 같은 양으로 분할 한 후 코어 당 하나의 프로세스를 시작하여 속도를 높일 수 있습니다.