multi thread 효과를 보려면 어떻게 해야 하나요??

trymp의 이미지


제가 1GB 넘는 파일을 암호화 하려고 하는데요. (블럭암호화)

이게 사이즈가 너무 커서 암호화하는데 소요시간이 많이 걸립니다.

그래서 파일의 각각 일정사이즈의 블럭만큼 나누어서 여러개의 thread 에서 나누어서

처리하려고 하는데요. ( 원본 파일 -> 암호화 파일 생성)

막상 나누어서 처리해 보니 암호화는 잘 되는데, 소요시간에 차이가 없더군요.

제가 만든 구상은 main 에서 파일을 읽어서 동적으로 할당된 부분에 담고

그것을 사용될 buff 와 length 그리고 write 할 파일의 offste 등의 정보를

thread 에 주어서 다중 처리하는 것입니다.

그런데, 소요시간이 단축이 안되네요.

여러개의 core 에서 CPU 를 쓰는 것은 확인했습니다.

어떤식으로 접근해야 multi thread 효과를 제대로 볼수 있을까요?

고수님들의 조언 부탁들려요

xylosper의 이미지

파일 IO에서 대부분의 시간이 경과하는게 아닌가요?
(제가 아는 한에서) 파일 IO는 필연적으로 락을 걸고 동기해줘야하기 때문에 멀티스레딩을 한다고 해서 더 빨리지진 않을겁니다.
파일을 읽고 쓰는데 걸리는 시간과, 메모리에 올라온내용을 암호화하는데 걸리는 시간을 따로 벤치마킹해보시는게 좋을듯합니다.

chadr의 이미지

디스크 I/O에서 다 잡아먹는다에 100원 겁니다.

가능한 메모리에서 모든 것을 한꺼번에 수행하시고 디스크에 기록할때는 한방에 연속된 공간에 기록되도록 해보세요.

즉, 모든 스레드에서 동시 다발적으로 디스크에서 읽고 다시 이걸 동시 다발적으로 디스크에 기록하지 마시고
디스크에서 읽을때는 스레드에서 작업할 수 있을 만큼 쭉~ 한방에 읽고, 스레드들이 다 작업이 끝나면 다시 이걸 한방에 쭉~ 기록하고...

이렇게 반복하도록 해보세요.

가장 큰 요점은 디스크의 seek타임을 줄이는 것입니다. 그렇기 위해서는 디스크 헤드가 최대한 적게 움직이고 최대한 디스크가 덜 회전하도록 해야합니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

상량의 이미지

공상적으로 추리해보기 보다는 프로파일러를 사용해서 어떤 exclusive function이 작동 시간을 가장 많이 잡아먹는지를 확인하는게 급선무라고 생각해요.

그리고 위엣분들이 말씀하신것처럼, 1GB정도의 파일은 구석기시대 컴퓨터가 아니라면 메모리에 모두 집어넣을 수 있으니까 그렇게 하는게 좋을것 같아요.

디스크IO도 있지만 RAM IO도 상당히 느리니까 혹시 사용하고 나서 string같은 컨테이너를 지운 다음에 다시 allocate하지는 않는지도 확인하는게 좋을듯해요

chadr의 이미지

1GB를 전부 메모리로 올리는건 별로 추천하지 않습니다. 1GB가 작은 용량같지만 그걸 전부 메모리에 올리려면 내부적으로 페이지 폴트 상당히 일어납니다. 페이지 폴트가 일어난다는 것은 엄청난 성능상 손해입니다.

만약에 1GB보다 큰 파일일 경우에는 더 힘들어지게 됩니다. 그렇게 된다는 것은 데이터 크기 1GB에서만 작동하는 안좋은 프로그램이 됩니다.

제가 말한건 1GB를 전부 올리는 것이 아닌 어느정도 적당한 크기만큼 메모리에 한꺼번에 읽고 그걸 스레드에게 분배하고 결과를 다시 디스크에 기록하는 방식입니다. 그런데 CPU가 연산하는 동안 디스크가 놀면 시간이 아깝지요. CPU가 연산하는 동안 디스크에서 데이터를 조금이라도 더 읽어 놓으면 그만큼 성능 향상에 도움이 됩니다.

가장 성능상 적절한 것은 스트리밍으로 연산과 동시에 데이터를 버퍼에 채워넣는 식으로 구현하여 CPU와 HDD가 쉴틈없이 작동하는 것입니다.
하지만 문제는 디스크에 읽고 쓰기 속도 때문에 CPU 연산속도를 못따라오는게 문제이지요.

이런 문제를 해결하기 위해서 분산처리라는 것이 생긴 것입니다. 그냥 단순히 생각하면 RAID striping으로 묶는 것이 그런 것에 해당됩니다.

그리고 RAM I/O가 느려서 string 같은 컨테이너가 할당한 메모리를 해제 하지마라 것이 아니라 운영체제에게 동적 메모리 할당을 요청하면 system call을 하게 되고 그것은 커널을 호출하게 되고 커널에서 sleep이 될 확률이 높아지기 때문입니다. sleep이 된다는 것은 운영체제에게 프로세스가 자신에게 할당된 time slice를 포기하게 된다는것과 동일합니다. 이는 다른 프로세스에게 컨텍스트가 넘어가게 되므로 다시 해당 프로세스로 제어가 넘어오기 전까지는 시간이 걸리므로 성능 하락으로 이어지게 됩니다.

이것은 RAM I/O하고는 관련이 없습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

상량의 이미지

페이지폴트는 시스템의 RAM메모리가 부족한 경우에만 일어나는 것으로 알고 있는데... 만약 타겟의 RAM이 1GB보다 적으면 문제가 되겠지만, 요즘 컴퓨터는 아무리 못해도 2GB은 기본으로 있는걸로 알고 있습니다. 또, 64비트 운영체제가 보금이되면서 사용 가능한램이 현실적으로 사용할 수 있는 만큼보다 더 많은게 보통입니다. 1GB 미만인 일부의 컴퓨터에서의 성능을 위해서 더 빠르고, 편하고, 실수하기 힘든 방법을 포기하는것은 옳지 않다고 생각합니다. 물론 질문자님의 상황을 제가 모르기 때문에 자세히 말하긴 힘들죠... 그런데 멀티스레드를 제대로 활용 할 수 있는 컴퓨터는 램 메모리도 충분할 것이라는 견해입니다.

HDD에서 순차적으로 파일을 읽으면서 동시에 처리하는것은 아무리 빨라도 RAM에서 파일을 읽고 처리를 하는것보다 느리니까...

만약에 읽어야 할 파일이 2 GB를 넘어가면 그때 가서 1GB씩 읽고 쓰면 될듯 합니다. 디스크에서 자주 조금씩 읽는것 보다 한꺼번에 많이 읽는게 성능이 더 좋은걸로 알고 있습니다. 아마 저라면 eof가 걸리기 전까지 1 기가바이트씩 RAM에 올리고, 아마 string 형식일 그 데이터의 일정 부분부터 다른 일정 부분까지 여러개의 스레드에 나누어줘서 처리하게 한 후에, 스레드를 모두 join하고 디스크에 출력을 한 후에 다시 1GB읽는 방법을 택할 것 같습니다.

chadr의 이미지

정확히 말하면 페이지 폴트는 시스템에 메모리가 부족할때 일어나는 것이 아니라 해당 가상 메모리를 접근했는데 실제 물리 페이지가 존재하지 않을때 발생하는 것입니다.

만약에 프로세스가 운영체제에게 메모리 할당을 요청합니다. 1기가를 했다 칩시다.
운영체제는 프로세스에게 큰 문제가 없는한 1기가 메모리를 할당했다고 알려줍니다.

그런데 진짜 그 1기가를 해당 프로세스가 다 쓸수 있게 물리 메모리를 할당할까요?

컴퓨터에는 1기가를 램에 올리는 프로세스만 도는게 아닙니다. 현재 시스템의 상황이 어떻게 될지도 모르는데 1기가를 모두 해당 프로세스에서 전용하여 사용할수는 없겠죠.

만약에 1기가를 A 프로세스가 다 쓸 수 있도록 물리 메모리를 할당했다 합시다.
그리고 만약에 B 프로세스가 1기가 메모리를 할당요청을 했다고 합시다.
시스템 메모리가 2기가밖에 안되는 시스템이라면 메모리가 부족하게 됩니다.

이 상태에서 A프로세스가 할당된 메모리에 데이터를 입출력하는 동시에 B라는 프로세스도 데이터를 입출력한다고 합시다.
시스템은 어떻게 될까요? A 프로세스로 컨텍스트 스위칭이 되었을 경우에는 A 프로세스가 메모리 입출력을 해야하므로
B라는 프로세스가 사용한 물리 메모리를 뺐어옵니다.(페이지 폴트 -> 스왑인) 동시에 B 프로세스가 사용한 메모리는 스왑아웃 합니다.
프로세스 time slice가 다 되서 이제 B프로세스로 컨텍스트가 넘어왔습니다. 마찬가지로 B프로세스도 메모리 입출력을 해야하므로
A 프로세스가 쓰던 메모리를 뺏어옵니다. 그리고 다시 A프로세스로 컨텍스트 스위칭...........................

시스템이 어떻게 될까요? 프로세스 두개 실행했다고 먹통이 되버렸습니다.
제대로 된 운영체제라면 이런 상황에 안빠지도록 해야합니다.

그래서 프로세스가 아무리 큰 메모리 할당을 요청했다고 해도 그걸 바로 물리 메모리로 반영 안합니다.
물론 윈도우즈에서는 바로 반영을 할 수 있는 방법을 제공하지만 그게 기본으로 동작하진 않습니다.

프로세스가 접근 했을때 물리 메모리가 없다면 그제서야 할당을 하게 되죠. 그게 바로 페이지 폴트입니다.
1기가 메모리를 할당 했을 경우에 거기에 열심히 데이터를 읽어서 넣게 되면 1기가 다 넣을때까지 페이지 폴트 계속 납니다.

하지만 작은 용량을 할당 받고 그걸 계속 공유해서 쓰면 처음 쓸때만 페이지 폴트 나고 그 다음부터는 안납니다.

그리고 만약에 1기가를 램에 모두 올리고 사용하도록 프로그램을 작성해 놓으면 해당 프로그램은 최소 시스템에 가용메모리가 1기가 이상은 있어야한다는 제약사항을 가지고 가게 됩니다.

그리고 하드에서 일부씩 읽어서 처리하고 기록하는 것하고 전체를 다 읽어서 처리하는것하고 무엇이 다른가요?

결국은 전자든 후자든 메모리에 1기가라는 데이터 용량이 모두 한번은 올라와야지 cpu가 처리합니다.

전자는 왠지 하드를 여러번 접근하는것 같고 후자는 하드를 한번 접근하는것 같이 느껴지나요?

즉, 전자는

하드 읽기 -> 데이터 처리 -> 하드 쓰기 -> 하드 읽기 -> 데이터 처리 -> 하드 쓰기 -> 하드 읽기 -> 데이터 처리 -> 하드 쓰기...........

후자는

하드 읽기 -> 데이터 처리 -> 하드 쓰기

설마 후자가 위에 써진 시나리오상 한번만 써졌으니 더 빠르다고 생각하시나요?
루프 돌며 시스템 콜 한번 더 호출하니 더 느리다고 주장하실건 아니라고 생각합니다.
프로그램을 이상하기 짜지 않는 이상 1바이트씩 fread하진 않습니다.

조금씩 읽어서 처리하나 다 읽어서 처리하나 싱글 코어 시스템에서는 결국은 똑같습니다.

디스크에서 데이터를 모두 램에 올리는 동안은 cpu는 그저 놀게 됩니다. 왜냐하면 데이터가 램에 모두 올라와야지만 그때서 연산을 할 수 있으니까요.
그리고 연산 결과를 디스크에 기록하는 동안도 cpu는 그저 놀게 됩니다.
그리고 cpu가 연산하는 동안 디스크는 그저 놀게 됩니다.

하지만 멀티 코어 시스템에서는 다릅니다. 동시 병렬성이라는것이 생기게 되지요.
디스크에서 조금씩 읽어서 빠르게 처리 스레드로 데이터를 전송합니다.
그러면 cpu는 디스크 입출력에 의존적이지 않게 자신 할일을 할 수 있게 됩니다.
그리고 디스크도 cpu에 의존적이지 않게 자신 할일을 할 수 있게 됩니다.

하지만 여기서 한가지 문제점이 있습니다. cpu와 디스크 속도가 매우 차이나게 되는 것이지요.
그것을 최대한 줄이는 것이 분산처리와 병렬처리 알고리즘의 핵심입니다.

그런데 1기가를 메모리에 전부 올려놓고 연산한다라......
페이지 폴트는 둘째치고 시스템 하드웨어를 제대로 못사용하는 것입니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

상량의 이미지

왜 시스템 하드웨어를 제대로 못 쓴다고 생각하시나요? ram을 절약하려고 Disk IO를 자주 부르는것이 오히려 성능을 저하시킬 수 있습니다.

RAM IO 속도가 디스크 IO의 약 16배인데, 디스크 IO는 순차적으로 밖에 접근 못합니다. 게다가 디스크는 조금씩 읽고 조금씩 쓰는것이 최악의 성능을 보여주는 경우입니다. 파일 복사를 할때 잘 알 수 있습니다. 1GB짜리 파일을 통으로 복사하는것과 4만개의 파일 1 GB를 복사하는것은 분명히 차이가 큽니다.
한편, 헤드가 다른곳에 가 있다가 읽어야 할 차레가 온다면 그런 대기시간도 있지 않겠습니까?
RAM이 부족한 (~2GB) 시스템이라면 모를까, 암호화를 위한 하드웨어가 어느 정도 갖춰져 있다면 RAM 1GB쯤은 페이징하지 않습니다. 특히 현대적인 OS (Win 7, Vista등)은 아무 이유 없이 잘 쓰고 있는 램 오브젝트를 버츄얼에 집어넣지 않습니다.

조금씩 읽고 조금씩 처리하는것의 최대 문제점은 디스크 IO랑 싱크로나이즈해야 한다는 것인데, 이게 쉽지 않은 일이라는것은 둘째치고, 싱크로가 멀티스레드 속도의 최대의 적이라고 할 수 있습니다. chadr님이 제안하시는 방법이라면 읽고 쓰는 스레드에 맞춰서 연산 스레드가 잠시 멈춰야 할 것입니다. 그에 비해 1 GB를 모두 RAM에 올리고 멀티스레드를 작동시키면 동시다발적으로 싱크로 필요 없이 처리할 수 있습니다. 방법도 쉽게 encrypt(const int& startRow, const int& endRow)식으로 해서 레이스컨디션도 사전에 차단할 수 있습니다.

멀티스레드를 할때의 중요한 원칙 하나는 최대한 적은 수의 스레드를 생성하면서 각 스레드에게 일을 많이 주는것 이라고 알고있습니다. join/wait등은 디스크 IO를 동시에 할때 필연적으로 일어나기 마련인데 스레드가 대기하는 시간은 멀티스레드에서의 속도 어드벤티지를 삭감하거나 무효화시킵니다.

+
하드 읽기 -> 데이터 처리 -> 하드 쓰기 -> 하드 읽기 -> 데이터 처리 -> 하드 쓰기 -> 하드 읽기 -> 데이터 처리 -> 하드 쓰기...........

후자는

하드 읽기 -> 데이터 처리 -> 하드 쓰기

:: 후자가 훨씬 빠르다고 생각합니다. 일단 딱 보기에도 간단하지 않습니까? 위에서 말한 이유도 있습니다. 적은 수의 파일을 옮기는것은 동량의 많은 수의 파일을 옮기는것보다 빠릅니다.

물론, 대상 컴퓨터가 램이 적으면 chadr님의 대안이 더 효과적일겁니다.

요약:
1. 램은 디스크보다 빠릅니다. 약 16배?
2. 디스크는 순차적으로, 그리고 적은 수의 파일을 읽고 쓰는것에 능하다. 그에 비해 RAM은 병렬하게 적은 양의 데이터를 자주 읽고 자주 씁니다.
3. 현대적인 시스템에서는 페이지폴트가 성능저하의 원인으로 흔히 꼽히지 않는걸로 알고 있습니다. 또, 물리 메모리가 충분하다는 전제하에서는 페이지폴트는 일어나지 않습니다. 사용중인 메모리일수록 일어나지 않고요.
4. 멀티스레드는 멈췄다 실행됐다하면 멀티스레드의 성능향상효과가 반감됩니다. Disk IO는 느리기 때문에 필연적으로 join/wait등을 넣게 되고, 그렇다면 성능이 저하됩니다.
5. 만약 시스템에 메모리가 2GB가량보다 적으면 chadr님의 방식이 더 효율적일겁니다.

수정: 그 1기가가 한 파일이 아니라 여러개의 파일이면 멀티스레드로 효과를 볼 수 있을것같습니다.

jick의 이미지

지금 문제는 1GB를 한번에 읽을 것인가 아니면 적당히 (예를 들어 64KB) 나눠 읽을까 하는 것입니다.

물론 1GB짜리 파일을 한번 읽는 것이 파일 4만개를 읽는 것보다는 훨씬 빠르겠죠. 하지만 파일 4만개를 읽는 것과 1GB짜리 파일 하나를 4만번에 나눠 읽는 것은 전혀 다른 문제죠. 후자는 오히려 1GB짜리 파일 하나를 한번에 읽는 것에 가깝습니다. (요즘 OS를 얘기하시는데 요즘 OS라면 당연히 미리 버퍼링을 할 것이므로 여러 번에 나눠 읽는다고 해도 OS가 적당히 "미리 읽을 수 있는만큼" 넉넉히 미리 읽어오게 됩니다.)

1기가를 한번에 읽는 것의 문제는 1기가를 읽을 동안 (그리고 처리된 데이터 1기가를 쓸 동안) CPU는 놀고 있다는 것입니다. 64KB씩 읽으면 처음 64KB를 읽은 다음부턴 CPU와 디스크가 동시에 일을 하게 됩니다. 프로그램을 제대로 짠다면 이게 더 느려질 이유가 없습니다.

상량의 이미지

조금씩읽히는것이야말로 CPU를 놀기합니다. 위에도 말했다시피 멀티스레드를 제대로 활용하려면 많은 양의 일을 끊기지 않고 연속적으로 맡기는게 좋습니다. 디스크에서 조금씩 읽으면 싱크로를 많이 하거나 (속도 저하), 스레드를 자주 스폰해야합니다 (속도 저하). 그리고 64KB는 되게 적은 양의 일인데, 그러면 스레드를 생성하는 시간이 이득을 무효화할것 같습니다.

chadr의 이미지

조금씩읽히는것이야말로 CPU를 놀기합니다.
-> 왜요? 예를 들어주세요.

위에도 말했다시피 멀티스레드를 제대로 활용하려면 많은 양의 일을 끊기지 않고 연속적으로 맡기는게 좋습니다.
-> 맞습니다.

디스크에서 조금씩 읽으면 싱크로를 많이 하거나 (속도 저하),
-> 싱크 할 필요 없습니다. 디스크에서 읽는 블럭들은 서로 의존성이 전혀 없습니다.

스레드를 자주 스폰해야합니다 (속도 저하).
-> 왜 스레드를 자주 스폰해야한다고 생각하시는지 모르겠네요. 스레드를 생성하고 계속 쓰면 됩니다.

그리고 64KB는 되게 적은 양의 일인데, 그러면 스레드를 생성하는 시간이 이득을 무효화할것 같습니다.
-> 1기가 파일이 모두 연속적으로 디스크에 저장 되어있을 보장은 어디에도 없습니다. 1기가 파일이 64kb씩 총 16000개로 단편화 되어있다고 한다면 어쩌실건가요?

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

chadr의 이미지

요약:
1. 램은 디스크보다 빠릅니다. 약 16배?
-> 맞습니다. 램은 디스크보다 무척 빠릅니다.

2. 디스크는 순차적으로, 그리고 적은 수의 파일을 읽고 쓰는것에 능하다. 그에 비해 RAM은 병렬하게 적은 양의 데이터를 자주 읽고 자주 씁니다.
-> 맞습니다. 램은 랜덤 엑세스에 매우 빠릅니다.

3. 현대적인 시스템에서는 페이지폴트가 성능저하의 원인으로 흔히 꼽히지 않는걸로 알고 있습니다. 또, 물리 메모리가 충분하다는 전제하에서는 페이지폴트는 일어나지 않습니다. 사용중인 메모리일수록 일어나지 않고요.
-> 왜 페이지 폴트가 성능 저하에 영향을 안끼친다고 생각하시는지요? 페이지 폴트가 일어나면 어떤 일이 일어나는지 한번 찾아보시길 권해드립니다. 이곳에 운영체제 이론 쓰기에는 너무 많은 양입니다.
-> 물리 메모리가 충분하다는 전제하에 페이지 폴트가 일어나는지 안일어나는지는 그냥 "작업관리자->프로세스->메뉴에서 보기->열선택->페이지 폴트, 페이지 폴트 변화량"을 켜고 한번 지켜보세요.
-> 페이지 폴트는 스왑아웃된 것이 스왑인 하는 경우만 발생하지 않습니다. 다시 말씀드리지만 페이지 폴트는 mmu가 해당 페이지에 접근했는데 해당 페이지가 물리 메모리에 매핑 되어있지 않으면 일어나는 것이 페이지 폴트입니다.

4. 멀티스레드는 멈췄다 실행됐다하면 멀티스레드의 성능향상효과가 반감됩니다. Disk IO는 느리기 때문에 필연적으로 join/wait등을 넣게 되고, 그렇다면 성능이 저하됩니다.
-> 왜 스레드를 종료했다가 다시 생성한다고 생각하시나요? 말씀하신데로 스레드를 종료했다가 다시 만드려면 비용이 많이 듭니다. 전 스레드를 재생성 한다는 말 안했습니다.

5. 만약 시스템에 메모리가 2GB가량보다 적으면 chadr님의 방식이 더 효율적일겁니다.
-> 제가 말씀드리는 방식은 메모리 크기에 별 상관없이 효율적인 방법이라는 것을 말씀드리고 싶네요.

수정: 그 1기가가 한 파일이 아니라 여러개의 파일이면 멀티스레드로 효과를 볼 수 있을것같습니다.
-> 1기가 파일이 통으로 있는 것을 엑세스 하는것과 1기가 파일이 100메가씩 10개로 나뉘는 것이 다르다고 생각하시는 것인가요?

왜 시스템 하드웨어를 제대로 못 쓴다고 생각하시나요? ram을 절약하려고 Disk IO를 자주 부르는것이 오히려 성능을 저하시킬 수 있습니다.
-> 전 램을 절약하고자 한다고 말한 적 없습니다. cpu와 디스크를 동시적으로 놀리지 않고 일 시키기기 위해 블럭단위로 나눠서 처리 하는 방식을 말하고 있습니다.

RAM IO 속도가 디스크 IO의 약 16배인데, 디스크 IO는 순차적으로 밖에 접근 못합니다. 게다가 디스크는 조금씩 읽고 조금씩 쓰는것이 최악의 성능을 보여주는 경우입니다. 파일 복사를 할때 잘 알 수 있습니다. 1GB짜리 파일을 통으로 복사하는것과 4만개의 파일 1 GB를 복사하는것은 분명히 차이가 큽니다.
한편, 헤드가 다른곳에 가 있다가 읽어야 할 차레가 온다면 그런 대기시간도 있지 않겠습니까?
-> 지금 이야기하는건 cpu와 디스크를 동시에 돌리는 것을 이야기 하고 있습니다. 파일 복사는 99% 디스크 I/O 성능에 의존적이므로 들어주신 예는 적절하지 않습니다.

RAM이 부족한 (~2GB) 시스템이라면 모를까, 암호화를 위한 하드웨어가 어느 정도 갖춰져 있다면 RAM 1GB쯤은 페이징하지 않습니다. 특히 현대적인 OS (Win 7, Vista등)은 아무 이유 없이 잘 쓰고 있는 램 오브젝트를 버츄얼에 집어넣지 않습니다.
-> 페이지 폴트는 스왑아웃 된것이 스왑인 되어야하는 경우만 발생되는게 아닙니다.

조금씩 읽고 조금씩 처리하는것의 최대 문제점은 디스크 IO랑 싱크로나이즈해야 한다는 것인데, 이게 쉽지 않은 일이라는것은 둘째치고, 싱크로가 멀티스레드 속도의 최대의 적이라고 할 수 있습니다.
-> 뭘 싱크 맞춰야한다는 것이지요? 디스크에서 읽어야할 블럭들은 서로 의존성이 없습니다.

chadr님이 제안하시는 방법이라면 읽고 쓰는 스레드에 맞춰서 연산 스레드가 잠시 멈춰야 할 것입니다.
-> 왜 연산스레드가 멈춰야하죠? 읽고 쓰는 스레드가 연산 결과를 복사해가서 독립적으로 저장하면 멈춰야할 이유가 없습니다. 연산결과를 복사해야 하는 비용이 걱정되신다면 걱정하실필요 없습니다. 말씀하신 것과 같이 메모리는 디스크보다 훨씬 빠릅니다.

그에 비해 1 GB를 모두 RAM에 올리고 멀티스레드를 작동시키면 동시다발적으로 싱크로 필요 없이 처리할 수 있습니다. 방법도 쉽게 encrypt(const int& startRow, const int& endRow)식으로 해서 레이스컨디션도 사전에 차단할 수 있습니다.
-> 제가 말씀드린 방법은 프로그램 실행 즉시 연산을 수행합니다. 하지만 말씀하신 방식은 각 phase마다 노는 하드웨어가 생깁니다.
-> 블럭을 나눠 여러개를 읽어서 각 스레드에서 처리해도 레이스 컨디션은 발생하지 않습니다. 디스크에서 읽는 블럭은 서로 의존성이 전혀 없습니다.

잘 이해가 안되신다면 파이프라인 이라는 것을 한번 찾아보세요.
제가 말씀드리는 것은 파이프라인과 비슷한 방식입니다.
전자는 파이프라이닝이 가능한 방식이며 후자는 파이프라이닝이 불가능한 방식입니다.

딱 보기에 간단하다고 그 방법이 훨씬 빠르진 않습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

상량의 이미지

아, 한 스레드에 I/O부분이 하나씩 있는건가요? 흠.

그래도 남는 문제들이, 파이프라인처럼 하는게 빠르지는 않다는것이랑, C++ std의 fstream/istream등을 기준으로 하면 읽기헤드의 위치를 여러 스레드가 공유할 수 없는것 같던데요? 한 파일을 한 프로그램만 읽을 수 있게 잠겨버리는데, 그러면 결국은 하나의 stream을 사이에 두고 wait해야하지 않을까 싶습니다. 게다가 계속 인정 안 하시는데, 한번 1 GB를 읽는것이 빠릅니다. SDD가 아닌 이상 성립하는 얘기입니다.

또, 하드웨어를 놀리지 않은것은 물론 중요하지만, 그것을 효율적으로 사용하는 것 또한 중요합니다. 하드드라이브는 연속적으로 읽는것이 효율적이고, CPU와 스레드는 아무리 미미하여도 io를 위해 wait이 없는게 중요하고, 또 프로그래밍은 단순한게 짜기도 쉽고 디버깅하기도 쉽습니다. 적어도 그렇게 생각합니다.

마지막으로, 페이지폴트 계속 언급하시는데, 제가 알기로 램이 충분히 있다면 버츄얼 메모리도, 페이지폴트도 생성 혹은 발생하지 않은 걸로알고 있습니다. 제 시스템(물론 RAM은 16GB라 조금 많은 편에 속하지만) 에 기록된 swap도 미미한 수준이고요.

여하튼 벤치마킹해보지 않고는 결론이 안 지어질듯 하네요.

chadr의 이미지

아, 한 스레드에 I/O부분이 하나씩 있는건가요? 흠.
-> 아니요. I/O 스레드는 하나입니다.

그래도 남는 문제들이, 파이프라인처럼 하는게 빠르지는 않다는것이랑
-> 왜 빠르지 않다고 계속 주장하시는지 모르겠습니다. 파이프라인에서 성능상 문제가 되는것은 stall이 되는 경우입니다. 당연히 파이프라인이 있는 요즘 cpu에서도 자원 공유를 위해서 동기화 개념이 반드시 들어갑니다.

C++ std의 fstream/istream등을 기준으로 하면 읽기헤드의 위치를 여러 스레드가 공유할 수 없는것 같던데요?
-> 말씀 드렸듯이 I/O 스레드는 하나입니다.

게다가 계속 인정 안 하시는데, 한번 1 GB를 읽는것이 빠릅니다. SDD가 아닌 이상 성립하는 얘기입니다.
-> 지금 제가 하는 이야기는 전체적인 처리 성능 관점에서 이야기하고 있습니다. 당연히 한번에 1기가를 읽으면 I/O 측면에서는 더 빠릅니다.
하지만 디스크에서 읽기만 하면 다 끝나나요? 메모리에 저장할때도 고려를 해야지요.

마지막으로, 페이지폴트 계속 언급하시는데, 제가 알기로 램이 충분히 있다면 버츄얼 메모리도, 페이지폴트도 생성 혹은 발생하지 않은 걸로알고 있습니다. 제 시스템(물론 RAM은 16GB라 조금 많은 편에 속하지만) 에 기록된 swap도 미미한 수준이고요.
-> 제가 말씀드린거 확인 해보시라니까요? 그리고 페이지 폴트는 램이 충분하다고 발생 안하는게 아니라까요? 알고 계신 사실이 틀리다고 하는데 좀 찾아보시라니까요? 리눅스 소스 까서 1시간 강의 해야지 인정하실건가요?

여하튼 벤치마킹해보지 않고는 결론이 안 지어질듯 하네요.
-> 벤치마킹 문제가 아니라 제가 말씀드리는 프로그램 구조를 아직 이해 못하신것 같습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

상량의 이미지

http://i.imgur.com/jbtPMt2.png

0,0,0,0,0,0,0,0. 1이 딱 하나 있네요. 제 PC는 3.7 quad intel i7, 64비트 Win 7, 그리고 16 GB의 램이 있습니다. RAM이 충분하기 때문에 평상시에는 페이지 폴트가 거의 읽어나지 않습니다.

제 OpenCL모델을 실행시켜보니까 처음에 30 PF/s이 있다가 점점 줄어들어서 나중에 0으로 안정화됩니다. 초당 60번씩 데이터를 GPU에서 CPU에게, 그리고 CPU에서 GPU에게 옮기는 것을 하고 있습니다.

http://en.m.wikipedia.org/wiki/Pipeline_(computing)#section_3
"As the assembly line example shows, pipelining doesn't decrease the time for a single datum to be processed;"
파이프라인 형식은 하나의 데이텀의 처리 속도를 높이지 않는다.

http://blog.scoutapp.com/articles/2011/02/10/understanding-disk-i-o-when-should-you-be-worried
"Disk latency is around 13ms, but it depends on the quality and rotational speed of the hard drive. RAM latency is around 83 nanoseconds."
바로 밑에
"This is why caching data in memory is so important for performance – the difference in latency between RAM and a hard drive is enormous*."

디스크를 조금씩 읽으려면 한번 읽어줄때 13 ms나 기다리야 합니다. RAM 은 83 ns 기다립니다. 대략 천배의 차이입니다. 또, 데이터를 RAM에 캐싱해줘야 성능이 향상된답니다. 물론 저게 reference가 완벽히 되진 않았지만, 저만 이렇게 생각하는게 아니라는겁니다.

왜 디스크가 느리다고 인정을 안 하시는건가요?;

또, 오히려 님께서 멀티스레드를 이해 못하시는것 같은데요... I/O가 한 스레드에서만 한다면 다른 스레드들과 싱크로 해야합니다. 안 그러면 access violation에러가 나겠죠. 싱크로하면 스레드가 멈춥니다. 그러면 성능은 창 밖으로 날라간거예요.

그에 비해서 데이터가 모두 램에 있으면 그 데이터 어레이를 스레드 수 만큼 나눠먹어서 처리하면 되는겁니다. 끊기지 않고, 동시다발적이면서 프로그램하기 간단합니다.

또, I/O가 현재 성능의 관건이잖습니까? 디스크에서 한번에 읽는것이 빠르다고 인정 하셨습니다. 그걸 모두 램에 집어 넣는 시간은 상대적으로 무시할 수 있는 시간입니다. 위에서 말했다시피 RAM의 대기시간은 83 ns이기 때문에 읽자마자 저장하는거라고 볼 수 있습니다. 또, 데이터를 로드하기 위해 디스크 헤드를 한번만 스핀하기 때문에 디스크 I/O시간도 줄어들고요. 스레드들은 독립, 고립된 채로 열심히 일하기 때문에 싱크로를 위해 멈춰야할 필요가 없습니다. 스레드의 최적의 상황인 연속적인 연산.처리가 가능한 상태가 된겁니다.

강조하자면,
디스크에서 여러번 조금씩 읽는것은 무진장 느리고, 현재 I/O bottleneck 문제기 때문에 그것을 해결하기 위해서 RAM에 올려놓는것입니다.

덧: 어떻게 만드는지에 따라 다르기 때문에, 그리고 확실하지않은 것은 탁상공론으로는 해결 못하기 때문에 벤치마킹이 최후의 수단이라고 생각하는 바 입니다.

jick의 이미지

죄송하지만 disk latency가 어떤 특성을 가지고 있는지, 쓰레드 간 동기화가 성능에 어떤 영향을 주는지 매우 피상적으로만 이해하고 계신 것 같습니다.

디스크 레이턴시가 13 ms라면, 1G짜리 파일을 10k씩 10만번 읽으면 1300초가 걸릴 거라고 생각하시는지요?

익명 사용자의 이미지

메모리 맵 파일을 사용해 보시는 건 어떨까요?

chadr의 이미지

자꾸 딴지거는 것 같긴합니다만......................
mmap을 쓰는것도 그렇게 추천하지는 않습니다.

작은 크기 파일이라면 상관 없습니다.

하지만 mmap이라는 것이 프로세스의 주소공간을 이용해서 매핑 하는 거라서 cpu가 지원하는 가상메모리 크기보다 큰 파일은 매핑을 못합니다.
물론 64비트로 하실 거라면 충분히 클테니 문제가 없을테지만요.

또한 mmap을 쓰더라도 동시다발적으로 여러 주소를 접근 한다는 것은 파일 관련 함수로 여러 군데를 seek하는것과 다를게 없습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

M.W.Park의 이미지

gain이 하나도 없는 것은 조금 이상하네요. 로직에 문제가 없다면 아마도 IO bound일 가능성이 높아보입니다.
확인을 위해서 램디스크에 파일을 옮겨서 시험해보거나,
파일을 여러 개로 쪼갠 후에 각 조각별로 single thread 방식의 프로그램을 여러 개 동시에 돌려서 시험 해보면 뭔가 결과가 달라질 것같네요.

-----
오늘 의 취미는 끝없는, 끝없는 인내다. 1973 法頂

익명 사용자의 이미지

일단은 기본적으로 모든 input 이 메모리에 있다고 가정하고 cpu 의 성능을 측정하고 또 순수 싱글 쓰레드 및 멀티 트레드에서 읽어오는 성능을 비교할필요가 있어 보입니다.

세부적인 내용이 없어서 모르겠지만 aesni 가 활성화된상태에서 aes 를 한다든지와 같이 io bound가 되는 현상이 발생해서 멀티 쓰레드의 이점을 발휘하지 못할수도 있습니다.

sunyzero의 이미지

위에 다른 분이 언급하신대로,
추측보단 프로파일러를 돌려보는 것이 좋습니다.

========================================
* The truth will set you free.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.