Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일
 

C# - 동기 방식이면서 비동기 메서드처럼 구현한 사례

일반 메서드를 필요하다면 Async로 만드는 방법은 Task 객체를 반환하도록 하면 됩니다. 가령, 5초 동안 스레드를 중지하는 다음의 메서드에 대해,

using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            new MyClass().Test();
        }
    }

    class MyClass
    {
        public void Test()
        {
            Thread.Sleep(1000);
        }
    }
}

TestAsync 메서드를 다음과 같이 만들어 줄 수 있습니다.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await new MyClass().TestAsync();
            Console.WriteLine("End");
        }
    }

    class MyClass
    {
        public Task TestAsync()
        {
            Task t = new Task(() => Thread.Sleep(1000));
            t.Start();
            return t;
        }
    }
}

그런데, Task 객체를 만들지 않으면서 Async 기능을 구현한 것처럼 만들 수도 있습니다. 이럴 때 TaskCompletionSource 객체를 사용하면 됩니다.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await new MyClass().TestAsync2();
            Console.WriteLine("End: TestAsync2");
        }
    }

    class MyClass
    {
        public Task TestAsync2()
        {
            TaskCompletionSource<object> src = new TaskCompletionSource<object>();

            try
            {
                Console.WriteLine("TestAsync2 called!");
                src.SetResult(null);
            }
            catch (Exception e)
            {
                src.SetException(e);
            }

            return src.Task;
        }
    }
}

뭐 저런 쓸모 없는 코드가 다 있나... 할 수 있습니다. 그런데 이런 쓸모없는 코드를 .NET BCL에서 찾아 볼 수 있습니다.

// System.Data.dll
// System.Data.Common.DbConnection

public virtual Task OpenAsync(CancellationToken cancellationToken)
{
    TaskCompletionSource<object> source = new TaskCompletionSource<object>();
    if (cancellationToken.IsCancellationRequested)
    {
        source.SetCanceled();
    }
    else
    {
        try
        {
            this.Open();
            source.SetResult(null);
        }
        catch (Exception exception)
        {
            source.SetException(exception);
        }
    }
    return source.Task;
}

위에서 보는 바와 같이 System.Data.Common.DbConnection은 OpenAsync 메서드를 제공하지만, 이름과는 달리 내부적으로 처리는 완전하게 동기로 하고 있습니다.

이런 바보 같은 코드가 왜 나왔을까요? 사실 DbConnection은 추상 클래스이기 때문에 기본적인 기능만 제공하는 정도입니다. 그리고 실질적인 기능들은 이를 상속받은 타입들이 하게 되는데, 자식 클래스들에게 비동기를 강제로(?) 구현하게 짐을 지우는 것이 어떤 경우에는 부담이 될 수 있습니다. 그래서, 인터페이스 측면에서 비동기 기능을 제공하는 가상 메서드는 제공하지만 동기처럼 동작하는 저런 구현이 나온 것입니다.

실제로 System.Data.SqlClient의 SqlConnection은 OpenAsync를 다시 구현하면서 비동기 기능을 완전하게 제공합니다.

그 외에도, 일정에 쫓겨 비동기 기능을 구현하진 못했지만 언젠가(?) 꼭 구현하리라 다짐하고 Async 메서드를 만들어 둔다면 저런 식으로 할 수 있을 것입니다. ^^




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





[최초 등록일: ]
[최종 수정일: 1/11/2018 ]

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

비밀번호

댓글 쓴 사람
 




... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
11833정성태5/14/20191532개발 환경 구성: 431. Visual Studio 2019 - CMake를 이용한 공유/실행(so/out) 리눅스 프로젝트 설정파일 다운로드1
11832정성태3/4/20191203오류 유형: 524. Visual Studio CMake - rsync: connection unexpectedly closed
11831정성태3/4/2019958오류 유형: 523. Visual Studio 2019 - 새 창으로 뜬 윈도우를 닫을 때 비정상 종료
11830정성태2/26/2019903오류 유형: 522. 이벤트 로그 - Error opening event log file State. Log will not be processed. Return code from OpenEventLog is 87.
11829정성태12/12/20191032개발 환경 구성: 430. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 - 리눅스 환경 [1]
11828정성태2/26/20192038개발 환경 구성: 429. Component Services 관리자의 RuntimeBroker 설정이 2개 있는 경우
11827정성태2/26/20191403오류 유형: 521. Visual Studio - Could not start the 'rsync' command on the remote host, please install it using your system package manager.
11826정성태2/26/20191065오류 유형: 520. 우분투에 .NET Core SDK 설치 시 패키지 의존성 오류
11825정성태2/25/20192987개발 환경 구성: 428. Visual Studio 2019 - CMake를 이용한 리눅스 빌드 환경 설정 [1]
11824정성태2/25/20191562오류 유형: 519. The SNMP Service encountered an error while accessing the registry key SYSTEM\CurrentControlSet\Services\SNMP\Parameters\TrapConfiguration. [1]
11823정성태2/21/20191077오류 유형: 518. IIS 관리 콘솔이 뜨지 않는 문제
11822정성태2/20/20191062오류 유형: 517. docker에 설치한 MongoDB 서버로 연결이 안 되는 경우
11821정성태2/20/20191164오류 유형: 516. Visual Studio 2019 - This extension uses deprecated APIs and is at risk of not functioning in a future VS update. [1]
11820정성태2/20/20193422오류 유형: 515. 윈도우 10 1809 업데이트 후 "User Profiles Service" 1534 경고 발생
11819정성태2/20/20191435Windows: 158. 컴퓨터와 사용자의 SID(security identifier) 확인 방법
11818정성태2/20/20191654VS.NET IDE: 131. Visual Studio 2019 Preview의 닷넷 프로젝트 빌드가 20초 이상 걸리는 경우 [2]
11817정성태2/17/20191345오류 유형: 514. WinDbg Preview 실행 오류 - Error : DbgX.dll : WindowsDebugger.WindowsDebuggerException: Could not load dbgeng.dll
11816정성태2/17/20191247Windows: 157. 윈도우 스토어 앱(Microsoft Store App)을 명령행에서 직접 실행하는 방법
11815정성태2/14/20191595오류 유형: 513. Visual Studio 2019 - VSIX 설치 시 "The extension cannot be installed to this product due to prerequisites that cannot be resolved." 오류 발생
11814정성태2/12/20191022오류 유형: 512. VM(가상 머신)의 NT 서비스들이 자동 시작되지 않는 문제
11813정성태2/12/20191276.NET Framework: 809. C# - ("Save File Dialog" 등의) 대화 창에 확장 속성을 보이는 방법
11812정성태1/2/2020945오류 유형: 511. Windows Server 2003 VM 부팅 후 로그인 시점에 0xC0000005 BSOD 발생
11811정성태2/11/20191364오류 유형: 510. 서버 운영체제에 NVIDIA GeForce Experience 실행 시 wlanapi.dll 누락 문제
11810정성태2/11/20191020.NET Framework: 808. .NET Profiler - GAC 모듈에서 GAC 비-등록 모듈을 참조하는 경우의 문제
11809정성태2/11/20191273.NET Framework: 807. ClrMD를 이용해 메모리 덤프 파일로부터 특정 인스턴스를 참조하고 있는 소유자 확인
11808정성태2/8/20191782디버깅 기술: 123. windbg - 닷넷 응용 프로그램의 메모리 누수 분석
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...