Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C# - 지연 실행이 꼭 필요한 상황이 아니라면 singleton 패턴에서 DCLP보다는 static 초기화를 권장

전에도 이에 대해 다룬 적이 있지만,

C# Singleton 인스턴스 생성
; https://www.sysnet.pe.kr/2/0/896

이번엔 간단한 성능 테스트를 해보겠습니다. DCLP(Double Checked Locking Pattern)로는 이렇게 코딩하고,

public class DCLP
{
    static DCLP _instance = null;
    static object _lock = new ();

    public int Add(int a, int b)
    {
        return a + b;
    }

    public static DCLP Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new();
                    }
                }
            }

            return _instance;
        }
    }
}

static 초기화 처리는 이런 식으로 할 텐데요,

public class CCtor
{
    static CCtor _instance = new CCtor();

    public int Add(int a, int b)
    {
        return a + b;
    }

    public static CCtor Instance
    {
        get
        {
            return _instance;
        }
    }
}

DCLP의 경우 코드도 길기 때문에 그냥 봐도 속도 면에서 불리해 보입니다. 게다가 static 초기화의 경우 단순한 인스턴스 반환이므로 JIT 컴파일 시 최적화로 인해 in-line 처리를 하므로 사실상 메서드 호출이 아닌, 값을 직접 사용하는 식으로 처리하기 때문에 비교 불가의 성능을 보입니다.

아래는 그 테스트 결과입니다.

int count = 1;
action(1, "touch-JIT", DCLPLoop, count);
action(1, "touch-JIT", CCtorLoop, count);

count = 500;
action(100000, "DCLPLoop", DCLPLoop, count);
action(100000, "CCtorLoop", CCtorLoop, count);

/* 출력 결과
touch-JIT : 0
touch-JIT : 0

DCLPLoop : 658
CCtorLoop : 30
*/

(첨부 파일은 이 글의 예제 코드를 포함합니다.)

의미상으로 보면, DCLP의 경우에도 if 문 처리 정도의 부하만 있을 듯하지만, 인라인 시킬 수 없다는 단점으로 인해 메서드 호출의 prologue/epilogue 코드 실행을 동반하면서 적어도 다음의 굵은 폰트 영역에 해당하는 코드는 매번 실행되는 부하를 갖게 됩니다.

public static DCLP Instance
    82:         {
    83:             get
    84:             {
    85:                 if (_instance == null)
00F00CA0 55                   push        ebp  
00F00CA1 8B EC                mov         ebp,esp  
00F00CA3 57                   push        edi  
00F00CA4 83 EC 20             sub         esp,20h  
00F00CA7 8D 7D DC             lea         edi,[ebp-24h]  
00F00CAA B9 07 00 00 00       mov         ecx,7  
00F00CAF 33 C0                xor         eax,eax  
00F00CB1 F3 AB                rep stos    dword ptr es:[edi]  
00F00CB3 83 3D F0 42 DE 00 00 cmp         dword ptr ds:[0DE42F0h],0  
00F00CBA 74 05                je          ConsoleApp2.DCLP.get_Instance()+021h (0F00CC1h)  
00F00CBC E8 BF F0 7C 73       call        746CFD80  
00F00CC1 33 D2                xor         edx,edx  
00F00CC3 89 55 E0             mov         dword ptr [ebp-20h],edx  
00F00CC6 83 3D 7C 35 A9 03 00 cmp         dword ptr ds:[3A9357Ch],0  
00F00CCD 75 6E                jne         ConsoleApp2.DCLP.get_Instance()+09Dh (0F00D3Dh)  
    86:                 {
    87:                     lock (_lock)
00F00CCF A1 80 35 A9 03       mov         eax,dword ptr ds:[03A93580h]  
00F00CD4 89 45 E0             mov         dword ptr [ebp-20h],eax  
00F00CD7 33 D2                xor         edx,edx  
00F00CD9 89 55 E4             mov         dword ptr [ebp-1Ch],edx  
00F00CDC 8D 55 E4             lea         edx,[ebp-1Ch]  
00F00CDF 8B 4D E0             mov         ecx,dword ptr [ebp-20h]  
00F00CE2 E8 69 77 C2 71       call        System.Threading.Monitor.Enter(System.Object, Boolean ByRef) (72B28450h)  
    88:                     {
    89:                         if (_instance == null)
00F00CE7 83 3D 7C 35 A9 03 00 cmp         dword ptr ds:[3A9357Ch],0  
00F00CEE 75 24                jne         ConsoleApp2.DCLP.get_Instance()+074h (0F00D14h)  
    90:                         {
    91:                             _instance = new();
00F00CF0 B9 9C 61 DE 00       mov         ecx,0DE619Ch  
00F00CF5 E8 FA 23 ED FF       call        CORINFO_HELP_NEWSFAST (0DD30F4h)  
00F00CFA 89 45 DC             mov         dword ptr [ebp-24h],eax  
00F00CFD 8B 4D DC             mov         ecx,dword ptr [ebp-24h]  
00F00D00 FF 15 DC 61 DE 00    call        dword ptr [Pointer to: CLRStub[MethodDescPrestub]@cdbb715500f004e5 (0DE61DCh)]  
00F00D06 8B 45 DC             mov         eax,dword ptr [ebp-24h]  
00F00D09 8D 15 7C 35 A9 03    lea         edx,ds:[3A9357Ch]  
00F00D0F E8 EC DE 42 73       call        7432EC00  
    92:                         }
    93:                     }
00F00D14 90                   nop  
00F00D15 C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],offset ConsoleApp2.DCLP.get_Instance()+078h (00h)  
00F00D1C C7 45 F0 FC 00 00 00 mov         dword ptr [ebp-10h],0FCh  
00F00D23 68 48 0D F0 00       push        offset ConsoleApp2.DCLP.get_Instance()+0A8h (0F00D48h)  
00F00D28 EB 00                jmp         ConsoleApp2.DCLP.get_Instance()+08Ah (0F00D2Ah)  
00F00D2A 0F B6 45 E4          movzx       eax,byte ptr [ebp-1Ch]  
00F00D2E 85 C0                test        eax,eax  
00F00D30 74 08                je          ConsoleApp2.DCLP.get_Instance()+09Ah (0F00D3Ah)  
00F00D32 8B 4D E0             mov         ecx,dword ptr [ebp-20h]  
00F00D35 E8 6D DD 42 73       call        7432EAA7  
00F00D3A 58                   pop         eax  
00F00D3B FF E0                jmp         eax  
    94:                 }
    95: 
    96:                 return _instance;
00F00D3D A1 7C 35 A9 03       mov         eax,dword ptr ds:[03A9357Ch]  
00F00D42 8D 65 FC             lea         esp,[ebp-4]  
00F00D45 5F                   pop         edi  
00F00D46 5D                   pop         ebp  
00F00D47 C3                   ret  

이런 면에서 볼 때, '지연 처리'가 절실하게 필요한 상황이 아니라면 static 초기화를 이용한 singleton 처리가 여러모로 장점을 갖습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 12/30/2020]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2024-06-13 09시26분
Reordering on an Alpha processor
; https://www.cs.umd.edu/~pugh/java/memoryModel/AlphaReordering.html

The "Double-Checked Locking is Broken" Declaration
; https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Lock-free algorithms: The singleton constructor
; https://devblogs.microsoft.com/oldnewthing/20110406-00/?p=11023

Lock-free reference-counting a TLS slot using atomics, part 1
; https://devblogs.microsoft.com/oldnewthing/20240612-00/?p=109887

Lock-free reference-counting a TLS slot using atomics, part 2
; https://devblogs.microsoft.com/oldnewthing/20240613-00/?p=109892

Lock-free reference-counting a TLS slot using atomics, part 3
; https://devblogs.microsoft.com/oldnewthing/20240614-00/?p=109902
정성태

... 136  137  138  139  140  141  142  143  144  145  146  147  [148]  149  150  ...
NoWriterDateCnt.TitleFile(s)
1351정성태9/13/201228112디버깅 기술: 49. windbg - .NET Framework 스레드 개체의 COM Apartment 유형 확인하는 방법
1350정성태9/12/201228796개발 환경 구성: 167. (실은) 무료가 아니었던 AWS EC2 서비스 [4]
1349정성태9/11/201260509VS.NET IDE: 74. Visual Studio의 '새 파일'을 UTF-8 인코딩으로 지정하는 방법 [4]
1348정성태9/11/201227979오류 유형: 164. Active Directory - Functional Level 승격이 안 되는 문제
1347정성태9/10/201230404Windows: 62. 윈도우 서버 2012 - Hyper-V 서버 마이그레이션 [1]
1346정성태9/10/201231249Windows: 61. 윈도우 서버 2012 - Active Directory 서버 마이그레이션
1345정성태9/10/201235282스크립트: 12. 파이썬 - Win32 DLL 연동 [2]
1344정성태9/10/201228438오류 유형: 163. .NET Framework 4.5 제거 후 Visual Studio 2010 실행 시 Unknown Error
1343정성태9/8/201242210스크립트: 11. 파이썬(Python) 윈도우 개발 환경 [7]
1342정성태9/6/201226406VS.NET IDE: 73. Visual Studio 2012 - XmlCodeGenerator 마이그레이션
1341정성태9/4/201235714Windows: 60. Hyper-V에서 RemoteFX 없이 DirectX 11 제공 [12]
1340정성태9/4/201227896개발 환경 구성: 166. DOS - ping 결과에서 평균 응답 시간값 추출하기 [3]
1339정성태9/4/201230336개발 환경 구성: 165. 새로운 Visual Studio 2012 원격 디버깅 툴 [5]
1338정성태9/4/201232140.NET Framework: 335. C# - (핸들을 이용하여) 모든 열린 파일을 열람 [6]파일 다운로드1
1337정성태8/30/201221956Phone: 7. 디버거로 실습해 보는 윈도우 폰의 Tombstone 상태파일 다운로드1
1336정성태8/30/201239994.NET Framework: 334. 스레드 비정상 종료로 발생하는 CLOSE_WAIT 소켓 상태 [2]파일 다운로드1
1335정성태8/30/201228760Windows: 59. Hyper-V Internal 네트워크 VM의 인터넷 접속
1334정성태8/29/201248075.NET Framework: 333. 코드로 재현하는 소켓 상태(FIN_WAIT1, FIN_WAIT2, TIME_WAIT, CLOSE_WAIT, LAST_WAIT) [6]
1333정성태8/27/201251478개발 환경 구성: 164. system32 폴더에 있는 파일의 권한 조정 [2]
1332정성태8/23/201223378Team Foundation Server: 48. TFS - Team Project Collection 이전하는 방법
1331정성태8/23/201226576오류 유형: 162. Database '...' already exists. Choose a different database name. (Microsoft SQL Server, Error: 1801)
1330정성태8/22/201227340Team Foundation Server: 47. 5인 이내의 팀, 또는 개인 로컬 소스 관리를 위한 무료 TFS Express
1329정성태8/21/201222750오류 유형: 161. Azure - Storage 삭제가 안되는 경우 [1]
1328정성태8/20/201233145개발 환경 구성: 163. IIS 7 - "MIME Types" 설정 아이콘이 없는 경우
1327정성태8/19/201237900Windows: 58. Windows 8 정식 버전을 설치해 보고... [14]
1326정성태8/19/201224218오류 유형: 160. Visual Studio 2010 Team Explorer 설치 오류
... 136  137  138  139  140  141  142  143  144  145  146  147  [148]  149  150  ...