C#을 사용하여 배치에서 비동기 API 호출 만들기

4183 단어 csharpapidotnet
데이터를 소비하기 위해 API를 호출하든 웹 스크래핑을 수행하든 때때로 API를 너무 세게 부수고 싶지 않아 IP 또는 계정이 차단되거나 호출이 실패할 수 있는 상황에 처할 수 있습니다. .

이 문서에서는 호출을 배치로 나누고 잠시 기다린 후 다음 배치를 호출하는 방법을 보여줍니다.

예시



이 데모 예제에서는 API를 25번 호출해야 하지만 동시에 모든 작업을 수행하고 싶지는 않은 요구 사항이 있습니다. 한 번에 10개의 비동기 호출을 일괄 처리하고 5번을 대기하고 싶습니다. 각 배치 사이의 초.

이 작업을 수행하는 작은 콘솔 앱here을 만들었으므로 자유롭게 복제하고 실행할 수 있습니다.

전제 조건



솔루션을 복제하고 f5 키를 눌러 시작할 수 있어야 합니다. RestSharp라는 너겟 패키지를 사용하여 API를 호출하고 데모 데이터를 제공하는 jsonplaceholder.typicode.com이라는 웹사이트를 호출한다고 언급하겠습니다.

실행할 쿼리 작성




var client = new RestClient("https://jsonplaceholder.typicode.com/comments");

            List<RestRequest> lstRestRequests = new List<RestRequest>();

            // this bit crafts the queries I want to call
            for (int i =0 ; i < 25; i++)
            {

                var request = new RestRequest(Method.GET);
                request.AddQueryParameter("postId", i.ToString());

                lstRestRequests.Add(request);
            }


위의 코드는 호출하고 저장하려는 25개의 쿼리를 생성합니다lstRestRequests.

목록을 분할




            // this list stores all my results
            List<IRestResponse> finishedTasks = new List<IRestResponse>();

            // split the list of queries into batches of 30 each
            var batchCalls = splitList(lstRestRequests, 10);


한 번에 25개 모두를 호출하고 싶지 않다는 점을 기억하세요. 10개의 여러 목록으로 분할하겠습니다. 이 예에서 batchCalls에는 3개의 목록이 있습니다. 처음 2개는 10개 호출이고 마지막은 5.

        // Splits a list into multiple smaller lists of specified batch size
        private static IEnumerable<List<T>> splitList<T>(List<T> locations, int size = 100)
        {
            for (int i = 0; i < locations.Count; i += size)
            {
                yield return locations.GetRange(i, Math.Min(size, locations.Count - i));
            }
        }


이 도우미 메서드는 목록을 더 작은 목록으로 나누는 작업을 수행합니다.

일괄적으로 전화 걸기




foreach (var batch in batchCalls)
            {
                //call each batch of 30 at the same time
                finishedTasks.AddRange(await Task.WhenAll(batch.Select(r => ExecuteRequest(r, client))));

                //after executing the current batch, wait 5 seconds
                await Task.Delay(5000);
                Console.WriteLine("taken time off, ready to go again");
            }

batchCalls를 반복하고 각 배치에 대해 batch.Select(r => ExecuteRequest(r, client)를 실행하여 모든 호출을 동시에 수행합니다.

라인finishedTasks.AddRange(await Task.WhenAll은 나중에 처리하기 위해 FinishedTasks에 모두 추가하기 전에 모든 호출이 완료될 때까지 기다린다는 의미입니다.

마지막으로 다음 배치로 이동하기 전에 5초 동안 대기하는 await Task.Delay(5000);가 있습니다.

// this method fires off the request
        private static Task<IRestResponse> ExecuteRequest(RestRequest r, RestClient client)
        {
            Console.WriteLine("Calling API " + r.Parameters[0]);
            return client.ExecuteAsync(r);
        }


참고로 ExecuteRequest 메서드는 API를 호출하는 것뿐입니다.

산출



실행하면 출력이 다음과 같아야 합니다. 일괄 호출을 수행하고 다음 일괄 처리로 이동하기 전에 잠시 기다립니다.



결과 활용




            foreach (var task in finishedTasks)
            {
                Console.WriteLine(task.Content.ToString());
            }


모든 일괄 처리가 실행되면 모든 응답이 finishedTasks에 저장됩니다. 그런 다음 데이터를 사용하여 필요한 모든 작업을 반복하고 수행하기만 하면 됩니다.

좋은 웹페이지 즐겨찾기