성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <br /> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# 4.0 - dynamic 키워드</div><br /> <br /> <br /> 아래의 재미있는 글이 있네요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Welcome to Dynamic C#(4) - 극과극 비교체험. ; <a target='_tab' href='http://vsts2010.net/114'>http://vsts2010.net/114</a> </pre> <br /> Reflection을 조금 깊게 아시는 분들이라면, 왠지 실험 결과가 그다지 공평한 것 같진 않음을 눈치채셨을 것입니다.<br /> <br /> 그래서, 저도 한번 테스트해보기로 했습니다.<br /> 제가 구성한 VPC에서 위의 소스 코드에서 제시한 대로 실행했을 때 다음과 같은 결과가 나왔습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Ctrl + F5 DEBUG빌드 Normal Time : 00:00:00.1815792 Dynamic Time : 00:00:00.4464240 Reflection Time : 00:00:11.3110800 </pre> <br /> 자, 이제 Reflection 부분을 개선해 보겠습니다. 우선, Dynamic(<a target='tab' href='https://www.sysnet.pe.kr/2/1/913'>초기 프로토타입</a>) 메서드 호출 부분을 Reflector로 분석해 보면 다음과 같이 구성되어 있는 것을 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > dynamic test = new Test(); test.FivePlusFive(); ==> 컴파일러에 의해서 다음과 같이 변경되어 출력 public void DynamicCall() { object test = new Test(); <b style='COLOR: blue'>if (<DynamicCall>o__SiteContainer0.<>p__Site1 == null)</b> { <DynamicCall>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(Binder.InvokeMember(0, "FivePlusFive", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) })); } <DynamicCall>o__SiteContainer0.<>p__Site1.Target.Invoke(<DynamicCall>o__SiteContainer0.<>p__Site1, test); } </pre> <br /> 가만히 보면, 별도의 dynamic 호출을 래퍼해주는 클래스를 컴파일 시에 생성해 주고 static으로 인스턴스를 보관해 두었다가 실행하고 있습니다.<br /> <br /> 오호... 거기서 벌써 ReflectionCall이 손해를 보고 있지요. 그래서 ReflectionCall도 다음과 같이 보정해 줄 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > <b style='COLOR: blue'>static MethodInfo methodInfo;</b> public void ReflectionCall() { Test test = new Test(); <b style='COLOR: blue'>if (methodInfo == null)</b> { Type type = test.GetType(); methodInfo = type.GetMethod("FivePlusFive"); } methodInfo.Invoke(test, BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, new object[] { }, CultureInfo.InvariantCulture); } </pre> <br /> 이렇게 해서 실행한 결과는?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Normal Time : 00:00:00.2387616 Dynamic Time : 00:00:00.4895616 Reflection Time : <b style='COLOR: blue'>00:00:06.9832752</b> </pre> <br /> 오호... 거의 절반으로 줄었습니다. 그래도 성능이 dynamic에 비하면 한참 떨어집니다. 개선의 여지가 있을까요?<br /> <br /> 조금 더 자세히 보면, dynamic method 호출은 그에 해당하는 다음과 같은 private static class를 만들어 주는 것을 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > [CompilerGenerated] private static class <DynamicCall>o__SiteContainer0 { // Fields public static CallSite<Action<CallSite, object>> <>p__Site1; } </pre> <br /> System.Runtime.CompilerServices.CallSite가 관여하는 것을 보면, 아마도 컴파일러에 의한 동적 코드 생성이 관여되지 않을까 예상이 됩니다. 요즘 많이들 사용하는 Unity나 Spring.NET 같은 유의 IoC컨테이너들이 Reflection으로 로드한 타입의 메서드 호출 속도를 빠르게 하기 위하여 동적으로 코드를 생성하는 것과 같은 방식이 사용되지 않을까 싶은데요.<br /> <br /> 이를 위해 .NET 2.0에 이미 소개되어 있는 Lightweight Code Generator(이하, LCG)를 사용해서 Reflection API를 좀 더 공평하게 개선을 해보겠습니다. (압니다... 알아요. LCG 사용하면 코드가 더 복잡해진다는 거. ^^;)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > delegate int FivePlusFiveDelegate(object Instance); static FivePlusFiveDelegate funcFivePlusFIve; public void ReflectionCall() { <b style='COLOR: blue'>Test test = new Test();</b> if (funcFivePlusFIve == null) { MethodInfo myMethodHandle = typeof(Test).GetMethod("FivePlusFive"); DynamicMethod dm = new DynamicMethod( Guid.NewGuid().ToString(), typeof(int), new Type[]{ typeof(object) }, typeof(Program), false); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, myMethodHandle); il.Emit(OpCodes.Ret); <b style='COLOR: blue'>funcFivePlusFIve = (FivePlusFiveDelegate) dm.CreateDelegate(typeof(FivePlusFiveDelegate));</b> } <b style='COLOR: blue'>funcFivePlusFIve(test);</b> } </pre> <br /> 결과는?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Normal Time : 00:00:00.1484736 Dynamic Time : 00:00:00.4454208 Reflection Time : <b style='COLOR: blue'>00:00:00.2798928</b> </pre> <br /> 이번엔, 오히려 dynamic 키워드가 2배 가까이 느린 것을 볼 수 있습니다.<br /> <br /> 엄밀히, LCG는 Reflection 범주라기보다는 동적 코드 생성에 가깝지요. 그렇긴 하지만, dynamic 키워드가 .NET 2.0에 소개된 LCG를 사용한 호출보다는 느리다는 것을 알 수 있습니다.<br /> <br /> 그래서... 결론이 바뀌죠? "<a target='_tab' href='http://vsts2010.net/114'>Welcome to Dynamic C#(4) - 극과극 비교체험.</a>" 글에서는 결론이 다음과 같이 나왔지요.<br /> <br /> <SPAN style='BACKGROUND-COLOR: #ccffcc; FONT-STYLE: italic; MARGIN: 10px 0px 10px 10px; WIDTH: 800px; FONT-FAMILY: 맑은 고딕, Consolas, Verdana; COLOR: #005555'><br /> 다이나믹이 리플렉션에 비해서는 월등히 빠르군요. 아마도 DLR의 힘을 빌려서 리플렉션 보다 훨씬 빠른 방식을 이용하는 것 같습니다. 이 부분에 대해서는 좀 조사를 해봐야 할거 같네요.<br /> </span><br /><br /> <br /> 반면에, 제가 말하고자 하는 결론은 오히려,<br /> <br /> <SPAN style='BACKGROUND-COLOR: #ccffcc; FONT-STYLE: italic; MARGIN: 10px 0px 10px 10px; WIDTH: 800px; FONT-FAMILY: 맑은 고딕, Consolas, Verdana; COLOR: #005555'><br /> dynamic 키워드가 DLR과의 호환을 위해 속도에서 손해를 보는 것일 뿐, DLR의 힘을 빌려서 리플렉션보다 훨씬 빠른 방식이 가능한 것은 아닙니다. 단순히 리플렉션의 속도를 개선하고자 하는 것이었다면, C# 컴파일러가 컴파일 시에 System.Runtime.CompilerServices.CallSite 등의 코드를 삽입하기보다는 오히려 LCG에 해당하는 코드를 넣었을 것입니다.</span><br /><br /> <br /> *** <a target='_tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=484&boardid=331301885'>첨부한 코드는 제가 변경한 프로젝트</a> 파일입니다. (물론, VS 2010에서 열어야 합니다.)<br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6044
(왼쪽의 숫자를 입력해야 합니다.)