C#에서는 닷넷 프레임워크 4.5이상에서 async, await이라는 기능을 활용해 

비동기 코드를 구현할 수 있습니다.

 

기존 동기식 코드는 라인단위로 실행이 되기 때문에, 앞에 코드가 끝나야 다음 코드로 넘어 갈 수 있습니다.

하지만, 비동기식 코드는 비동기 코드 실행시 다음 라인으로 넘어가 코드가 실행됩니다. 

한 번 요청을 해놓고 해당 결과와 상관없이 곧바로 다음 로직 들을 수행 할 수 있기 때문에, 때때로 효율적인 코드를 작성 할 수 있습니다.

 

C#에서 async , await 키워드로 비동기 코드 테스트 


Doasync()

DosyncSecond()  

2개의 비동 함수를 정의했습니다. 비동기 키워드를 정의하기 위해선 async키워드를 메소드 생성시 삽입해주어야 합니다.

그리고, 메소드 내부에 await 키워드로 특정 로직이 수행 될 수 있도록 대기 하는 로직을 주어야 합니다.

 

또한, 메소드 수행의 결과를 기다릴 수도 있고, 기다리지 않을 수도 있습니다.

메소드 바깥에 메소드 수행이 완료되는 것을 기다릴 거라면 await 결과값저장변수 와 같이 선언해

대기하는 구간을 만들어 주어야 합니다.

 

아래 코드는 Doasync() ,DosyncSecond() 가 연속적으로 요청되며 응답을 기다리지 않고, 

다음 라인의 Console에 문자를 찍는 3개의 로직이 바로 수행됩니다. 콘솔찍는 3개의 로직이 수행되면,

await k에서는 Doasync()함수가 종료될때까지 기다리며, 종료된 이후에 다음라인인

await k2로 넘어가 DoasyncSecond()함수가 종료될때까지 기다립니다.

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

namespace Async
{
    class Program
    {
        static async Task Main(string[] args)
        {
            
            Task k  = Doasync();
            Task k2 = DoasyncSecond();
            Console.WriteLine("비동기 메소드 2개를 요청하자 마자 바로 여기로 이동");
            Console.WriteLine("동기 코드 수행");
            Console.WriteLine("동기 코드 수행2");
            await k;
            await k2;
            Console.WriteLine("비동기기 코드 모두 종료된 후 수행");
            
        }

        public static async Task Doasync()
        {

            await Task.Run( () =>
            {                
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("Doasync");
                }
            });
        }

        public static async Task DoasyncSecond()
        {            
            await Task.Run( () =>
            {
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("DoasyncSecond");
                }
            });
        }



    }
}

 결과는 아래와 같습니다.

Doasync() ,DosyncSecond()를 먼저 요청했음에도, 비동기 메소드이기 때문에 바로 다음라인들의 로직이 수행되게 됩니다. 그리고, await키워드를 메소드 바깥에 설정해 두었기 때문에 비동기 메소드 2개가 모두 종료될때까지 기다린 후 

최종 모두 수행되면 마지막 Consle.WriteLine()함수를 실행하며 프로그램이 종료되게 됩니다.

 

비동기 코드 수행을 기다리지 않으려면? 


await키워드를 사용하지 않으면, 비동기 메소드 수행을 기다리지 않을 수 있습니다. 

await키워드가 설정된 라인에 주석을 치면,

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

namespace Async
{
    class Program
    {
        static async Task Main(string[] args)
        {
            
            Task k  = Doasync();
            Task k2 = DoasyncSecond();
            Console.WriteLine("비동기 메소드 2개를 요청하자 마자 바로 여기로 이동");
            Console.WriteLine("동기 코드 수행");
            Console.WriteLine("동기 코드 수행2");
            //await k;
            //await k2;
            Console.WriteLine("비동기기 코드 모두 종료된 후 수행");            
        }

        public static async Task Doasync()
        {

            await Task.Run( () =>
            {                
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("Doasync");
                }
            });
        }

        public static async Task DoasyncSecond()
        {            
            await Task.Run( () =>
            {
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("DoasyncSecond");
                }
            });
        }



    }
}

 

아래와 같이 비동기 메소드 요청을 보냈으나, 메소드 수행완료를 기다리지 않기 때문에, 

메소드가 요청만 보내고 프로그램은 그냥 종료되어 버립니다.

2개의 비동기 메소드에 Thread.Sleep(100)을 걸어두었기 때문에 프로그램 전체 종료가 100ms 이내에 일어 나기 때문에

비동기 메소드 내부의 Console.WriteLine()에 가지도 못하고 프로그램이 종료되게 됩니다. 

 

기다릴 필요가 굳이 없는 로직 수행이 필요할 경우 await키워드 없이 사용 할 수 있겠습니다.

 

 

 

async 비동기 메소드의 결과값이 필요한 경우


Doasync() 함수의 리턴 타입을 Task<string>으로 설정해주고, return 값에 string 문자열을 넣어주었습니다.

이렇게 한 후, await k 키워드로 메소드가 끝날때까지 기다려주도록 하고 결과값을 result변수에 저장합니다.

그리고, 최종적으로 콘솔에 출력합니다.

 

아래 코드를 실행하면, Doasync() 비동기 메소드의 return값을 가져올 수 있는 것을 확인 할 수 있습니다.

비동기로 동시에 요청해서 결과값 반환을 기다리도록 하면 동기 코드보다 훨씬 효율적으로 로직을 구성 할 수 있을 것 같습니다.

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

namespace Async
{
    class Program
    {
        static async Task Main(string[] args)
        {
            
            Task<string> k  = Doasync();
            Task k2 = DoasyncSecond();
            Console.WriteLine("비동기 메소드 2개를 요청하자 마자 바로 여기로 이동");
            Console.WriteLine("동기 코드 수행");
            Console.WriteLine("동기 코드 수행2");
            //await k;
            //await k2;
            Console.WriteLine("비동기기 코드 모두 종료된 후 수행");

            string reuslt = await k;//비동기 메소드의 실행결과를 result 변수에 저장함
            Console.WriteLine(reuslt); 
        }
        
        public static async Task<string> Doasync()
        {

            await Task.Run( () =>
            {                
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("Doasync");
                }
            });

            return "Task<string>으로 결과값을 받아보자";
        }

        public static async Task DoasyncSecond()
        {            
            await Task.Run( () =>
            {
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("DoasyncSecond");
                }
            });
        }



    }
}

 

LIST
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기