C#에서 HttpClient를 활용해 비동기 웹 요청을 해보도록 하겠습니다.

 

지난 포스팅 중 Line notify 를 보내는 예제를 활용해 보도록하겠습니다.

 

https://vmpo.tistory.com/90

 

C#으로 Line notify 보내기 (라인 메시지 보내기)

C#으로 라인 메시지 보내기 샘플입니다. *참고 : python으로 line notify를 사용했던 샘플입니다. 필요하시면 확인해주세요. https://vmpo.tistory.com/87 python으로 Line notify (라인 메시지) 보내기 파이썬 및..

vmpo.tistory.com

 

HttpClient로  LINE알림 비동기로 호출해보기


아래 코드는 비동기로 라인 메시지를 보내는 코드입니다.

Header설정은 DefaultRequestHeaders.add()를 통해 name, value를 각각 추가해줍니다.

Post 호출의 경우 파라미터를 같이 Dictionary<string,string> 형태로 저장을 해준 뒤,

FormUrlFormUrlEncodedContent 객체 생성시 파라미터로 전달해줍니다.

최종적으로 PostAsync("url", "전달할내용") 메소드를 호출해 줍니다. 

PostAsync 호출시에는 await 키워드를 넣어줘야 리턴값을 확인해 줄 수 있습니다.

public static async Task<HttpResponseMessage> PostAsyncHttp()
{
    HttpClient _httpClient = new HttpClient();            
    _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer Ask2OVGx4Jm9mUvcSLmfv1nY");

    var parameters = new Dictionary<string, string>();
    parameters.Add("message", "안녕하세요");
    var encodedContent = new FormUrlEncodedContent(parameters);

    var response = await _httpClient.PostAsync("https://notify-api.line.me/api/notify", encodedContent).ConfigureAwait(false);
    return response;
}

 

위 메소드를 비동기로 라인메시지 보내는 API를 3번 연속 호출한 후 비동기 메소드가 처리되는 동안 거의 동시에

FOR문을 수행하는 코드를 작성해보겠습니다.

비동기 메소드 내부에 Console.WriteLine()을 찍어 수행여부를 확인해 주도록 했습니다.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {

        static async Task Main(string[] args)
        {
            
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Console.WriteLine("비동기 3회 시작");
            Task<HttpResponseMessage> first  = PostAsyncHttp();
            Task<HttpResponseMessage> second = PostAsyncHttp();
            Task<HttpResponseMessage> third  = PostAsyncHttp();

            for(int i = 0; i < 10; i++)
            {                
                Console.WriteLine("다른 로직 수행 : " + i);                
            }

            HttpResponseMessage fr = await first;
            HttpResponseMessage sec = await first;
            HttpResponseMessage th = await first;

            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds+"ms");

            Thread.Sleep(5000);
        }
        

        public static async Task<HttpResponseMessage> PostAsyncHttp()
        {
            HttpClient _httpClient = new HttpClient();            
            _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer Ask2O1C1EUq0iNdBGAVGx4Jm9mUvcSLmfvgV61OH1nY");

            var parameters = new Dictionary<string, string>();
            parameters.Add("message", "안녕하세요");
            var encodedContent = new FormUrlEncodedContent(parameters);

            var response = await _httpClient.PostAsync("https://notify-api.line.me/api/notify", encodedContent).ConfigureAwait(false);
            Console.WriteLine("비동기 PostAsyncHttp() 호출");
            return response;
        }

    }
}

 

실행결과 비동기 메소드를 3번 요청한 후 for문을 수행하는 동안 각 비동기 메소드들이 호출된 모습입니다.

 

라인 메시지도 3건이 온 것을 확인 할 수 있습니다.

 

1회 호출과 3회 비동기 호출 수행시간 비교하기


3개의 비동기 메소드 포함 전체 로직 수행시간이 729ms인 것을 확인 할 수 있는데요.

비동기 메소드 1회 실행시의 수행 시간과 한 번 비교해 보겠습니다.

 

2개 메소드의 주석을 치고 1번만 호출해보겠습니다.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {

        static async Task Main(string[] args)
        {
            
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Console.WriteLine("비동기 3회 시작");
            Task<HttpResponseMessage> first  = PostAsyncHttp();
            //Task<HttpResponseMessage> second = PostAsyncHttp();
            //Task<HttpResponseMessage> third  = PostAsyncHttp();

            for(int i = 0; i < 10; i++)
            {                
                Console.WriteLine("다른 로직 수행 : " + i);                
            }

            HttpResponseMessage fr = await first;
            //HttpResponseMessage sec = await first;
            //HttpResponseMessage th = await first;

            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds+"ms");

            Thread.Sleep(5000);
        }
        

        public static async Task<HttpResponseMessage> PostAsyncHttp()
        {
            HttpClient _httpClient = new HttpClient();            
            _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer Ask2O1C1EUq0iNdBGAVGx4Jm9mUvcSLmfvgV61OH1nY");

            var parameters = new Dictionary<string, string>();
            parameters.Add("message", "안녕하세요");
            var encodedContent = new FormUrlEncodedContent(parameters);

            var response = await _httpClient.PostAsync("https://notify-api.line.me/api/notify", encodedContent).ConfigureAwait(false);
            Console.WriteLine("비동기 PostAsyncHttp() 호출");
            return response;
        }

    }
}

 

실행시간이 770ms인 것을 확인 할 수 있습니다. 여러번 프로그램을 다시 빌드해봐도 비슷한 시간이 측정됩니다.

3회 호출 했을때와 거의 차이가 없는 것을 알 수 있습니다.

동기식 실행시에는 1회 수행결과 * 3배의 수행시간이 걸리는 것에 비해 

비동기 요청으로 처리 할 경우 1/3로 실행시간을 줄일 수 있습니다.

10회 호출과  비교하기


10번을 비동기로 요청해보겠습니다.

10번의 메소드를 요청해놓고 다음 코드 실행을 위해 기다리지 않기 때문에,

시간차이는 요청로직을 수행하는 정도의 차이만 발생하는 것을 알 수 있습니다.

 

코드 스니펫 복사

 

Task.WhenAll를 활용해 비동기 메소드 호출 결과 처리하기


비동기 메소드 호출 후 각 메소드의 결과마다 await을 설정해 대기하지 않고,

미리 LIST로 담은 후 Task.Whenall(list)로 처리 할 수 있습니다.

 

아래 코드를 확인해보면 Task.WhenAll 라인에서 모든 요청이 종료될때까지 대기되며, 완료된 이후에

다음라인이 실행됩니다. 모든 비동기 요청의 결과 값은 HttpResponseMessage[] 배열에 저장 되어

필요한 경우 꺼내 쓰면 됩니다.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {

        static async Task Main(string[] args)
        {
            
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Console.WriteLine("비동기 3회 시작");
            Task<HttpResponseMessage> first  = PostAsyncHttp();
            Task<HttpResponseMessage> second = PostAsyncHttp();
            Task<HttpResponseMessage> third  = PostAsyncHttp();
            Task<HttpResponseMessage> test1 = PostAsyncHttp();
            Task<HttpResponseMessage> test2 = PostAsyncHttp();
            Task<HttpResponseMessage> test3 = PostAsyncHttp();
            Task<HttpResponseMessage> test4 = PostAsyncHttp();
            Task<HttpResponseMessage> test5 = PostAsyncHttp();
            Task<HttpResponseMessage> test6 = PostAsyncHttp();
            Task<HttpResponseMessage> test7 = PostAsyncHttp();

            List<Task<HttpResponseMessage>> list = new List<Task<HttpResponseMessage>>();
            list.Add(first);
            list.Add(second);
            list.Add(test1);
            list.Add(test2);
            list.Add(test3);
            list.Add(test4);
            list.Add(test5);
            list.Add(test6);
            list.Add(test7);

            for (int i = 0; i < 10; i++)
            {                
                Console.WriteLine("다른 로직 수행 : " + i);                
            }

            HttpResponseMessage[] response = await Task.WhenAll(list);

            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds+"ms");

            Thread.Sleep(5000);
        }
        

        public static async Task<HttpResponseMessage> PostAsyncHttp()
        {
            HttpClient _httpClient = new HttpClient();            
            _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer Ask2O1C1EUq0iNdBGAVGx4Jm9mUvcSLmfvgV61OH1nY");

            var parameters = new Dictionary<string, string>();
            parameters.Add("message", "안녕하세요");
            var encodedContent = new FormUrlEncodedContent(parameters);

            var response = await _httpClient.PostAsync("https://notify-api.line.me/api/notify", encodedContent).ConfigureAwait(false);
            Console.WriteLine("비동기 PostAsyncHttp() 호출");
            return response;
        }

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