성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - 재귀호출을 스택 자료구조와 반복문을 이용해 대체하는 방법을 Paralle.For와 함께?</h1> <p> 아래의 글에 대해,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - 재귀호출을 스택 자료구조와 반복문을 이용해 대체하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1599'>http://www.sysnet.pe.kr/2/0/1599</a> </pre> <br /> <a target='tab' href='http://blog.naver.com/techshare/100203865105'>Parallel.For를 이용한 재귀호출에도 사용이 가능하냐는 질문</a>이 있었습니다. 예제로 보내온 소스코드는 다음과 같은데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MonteCarlo { class Program { static void Main(string[] args) { double dblSt = 0, dblEn = 0; Console.Write("Input the Start and End Value for Integration: "); string strBuff = Console.ReadLine(); string[] strParams = strBuff.Split(' '); dblSt = double.Parse(strParams[0]); dblEn = double.Parse(strParams[1]); double dblInt = MonteCarloIntegral((x) => { return (x + Math.Sin(x)); }, dblSt, dblEn); Console.WriteLine("The Integration Result = {0}", dblInt); Console.ReadKey(); } static double MonteCarloIntegral(Func<double, double> Func, double Init, double Fin) { double dblVolume = Fin - Init, dblIntg = 0; if (dblVolume <= 0.05) // Monte Carlo Integration: I = integral f(x) dx = (1/n) * Sum(i = 1 to n) f(x[i]) { Random rndRand = new Random(100); long lngTrial = 10000 * ((long) ((Func(Fin) - Func(Init)) / dblVolume) + 1); for (long cnt = 0; cnt < lngTrial; cnt++) // Using I = integral f(x) dx = integral f(x(t)) * dx(t)/dt dt { double dblRand = rndRand.NextDouble(); double dblReal = Math.Sqrt((dblRand * dblVolume * (Fin + Init)) + Math.Pow(Init, 2)); dblIntg += (Math.Pow(Fin, 2) - Math.Pow(Init, 2)) * Func(dblReal) / (2 * dblReal); } dblIntg /= lngTrial; } else { double[] dblPartSums = new double[8]; double dblPartVol = dblVolume / dblPartSums.Length; <span style='color: blue; font-weight: bold'> Parallel.For(0, dblPartSums.Length, (cnt) => { double dblStart = Init + (cnt * dblPartVol), dblEnd = Init + ((cnt + 1) * dblPartVol); dblPartSums[cnt] = MonteCarloIntegral(Func, dblStart, dblEnd); });</span> dblIntg += dblPartSums.Sum(); } return dblIntg; } } } </pre> <br /> 정말 가능한지... 한번 해볼까요? ^^<br /> <br /> 우선, 예제 코드를 쉽게 이해할 수 있도록 병렬처리를 원래의 for 루프로 돌려놓겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > double[] dblPartSums = new double[8]; double dblPartVol = dblVolume / dblPartSums.Length; <span style='color: blue; font-weight: bold'>for (cnt i = 0; cnt < dblPartSums.Length; cnt ++) { double dblStart = Init + (cnt * dblPartVol), dblEnd = Init + ((cnt + 1) * dblPartVol); dblPartSums[cnt] = MonteCarloIntegral(Func, dblStart, dblEnd); }</span> dblIntg += dblPartSums.Sum(); </pre> <br /> 그럼, 이제 그다지 어렵지 않게 Stack + 반복문 유형으로 바꿀 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public struct SnapShotStruct { public double Init; public double Fin; public double dblVolume; public double dblIntg; public int stage; } static double MonteCarloIntegralLoop(Func<double, double> Func, double Init, double Fin) { double retVal = 0.0; Stack<SnapShotStruct> snapshotStack = new Stack<SnapShotStruct>(); SnapShotStruct currentSnapshot = new SnapShotStruct(); currentSnapshot.Init = Init; currentSnapshot.Fin = Fin; currentSnapshot.dblVolume = 0; currentSnapshot.dblIntg = 0; currentSnapshot.stage = 0; snapshotStack.Push(currentSnapshot); while (snapshotStack.Count != 0) { currentSnapshot = snapshotStack.Pop(); switch (currentSnapshot.stage) { case 0: currentSnapshot.dblVolume = currentSnapshot.Fin - currentSnapshot.Init; if (currentSnapshot.dblVolume <= 0.05) { Random rndRand = new Random(100); long lngTrial = 10000 * ((long)((Func(currentSnapshot.Fin) - Func(currentSnapshot.Init)) / currentSnapshot.dblVolume) + 1); for (long cnt = 0; cnt < lngTrial; cnt++) { double dblRand = rndRand.NextDouble(); double dblReal = Math.Sqrt((dblRand * currentSnapshot.dblVolume * (currentSnapshot.Fin + currentSnapshot.Init)) + Math.Pow(currentSnapshot.Init, 2)); currentSnapshot.dblIntg += (Math.Pow(currentSnapshot.Fin, 2) - Math.Pow(currentSnapshot.Init, 2)) * Func(dblReal) / (2 * dblReal); } currentSnapshot.dblIntg /= lngTrial; retVal += currentSnapshot.dblIntg; continue; } currentSnapshot.stage = 1; snapshotStack.Push(currentSnapshot); <span style='color: blue; font-weight: bold'> int length = 8; double dblPartVol = currentSnapshot.dblVolume / length; for (int i = 0; i < length; i++) { double dblStrt = currentSnapshot.Init + (i * dblPartVol); double dblEnd = currentSnapshot.Init + ((i + 1) * dblPartVol); SnapShotStruct newSnapShot = new SnapShotStruct(); newSnapShot.Init = dblStrt; newSnapShot.Fin = dblEnd; newSnapShot.stage = 0; snapshotStack.Push(newSnapShot); }</span> break; case 1: retVal = currentSnapshot.dblIntg + retVal; continue; } } return retVal; } </pre> <br /> Stack + 반복문으로 구현된 이 코드를 이제 원래의 Parallel.For로 돌려보면 어떻게 될까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > int length = 8; double dblPartVol = currentSnapshot.dblVolume / length; <span style='color: blue; font-weight: bold'>Parallel.For(0, length, (idx) =></span> { double dblStrt = currentSnapshot.Init + (idx * dblPartVol); double dblEnd = currentSnapshot.Init + ((idx + 1) * dblPartVol); SnapShotStruct newSnapShot = new SnapShotStruct(); newSnapShot.Init = dblStrt; newSnapShot.Fin = dblEnd; newSnapShot.stage = 0; snapshotStack.Push(newSnapShot); }); </pre> <br /> 별 쓸모가 없죠? ^^ 물론 이렇게 바꾼다고 해서 해답이 달라지는 것은 아닙니다. 하지만, 재귀호출을 Stack + 반복문으로 고치는 것 자체가 함수 호출을 리스트 형식으로 직렬화하는 것과 유사하기 때문에 Parallel.For를 호출하는 것도 역시 목록에 포함시켜 다음에 실행하도록 스케쥴링하는 것에 불과하므로 그다지 효용성이 없습니다.<br /> <br /> 만약 위의 코드를 굳이 병렬화 되도록 고쳐야 한다면 Parallel.For 내의 코드를 별도의 함수 처리로 바꿔야 하고 이는 다시 메서드의 재귀호출로 이어지기 때문에 결국 바꾸기 전과 후의 차이가 없게 됩니다.<br /> <br /> 그나저나, 이번 질문을 통해서 새롭게 알게 되는군요. 재귀호출이 loop 내에서 불려지는 경우, 재귀호출 방법으로는 병렬화가 가능하지만 Stack + 반복문으로 처리하는 경우 병렬화 처리가 무의미하다는 것!<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=819&boardid=331301885'>위의 처리 코드는 첨부 파일에 넣어두었으니</a> 참고하세요.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1637
(왼쪽의 숫자를 입력해야 합니다.)