여러 비동기 서비스를 동시에 호출 때문에 여기서 사용할 수 없다고 생각

서로 의존하지 않는 비동기 REST 서비스가 거의 없습니다. 즉, Service1의 응답을 “대기”하는 동안 Service2, Service3 등을 호출 할 수 있습니다.

예를 들어 아래 코드를 참조하십시오.

var service1Response = await HttpService1Async();
var service2Response = await HttpService2Async();

// Use service1Response and service2Response

이제 service2Response의존하지 않으며 service1Response독립적으로 가져올 수 있습니다. 따라서 두 번째 서비스를 호출하기 위해 첫 번째 서비스의 응답을 기다릴 필요가 없습니다.

Parallel.ForEachCPU 바인딩 작업이 아니기 때문에 여기서 사용할 수 없다고 생각 합니다.

이 두 연산을 병렬로 호출하기 위해 use 호출 할 수 Task.WhenAll있습니까? 내가 사용하는 한 가지 문제 Task.WhenAll는 결과를 반환하지 않는다는 것입니다. 모든 작업이 이미 완료되었고 응답을 가져 오기 위해 필요한 모든 작업을 수행 task.Result한 후 호출 한 후 호출 할 수 있습니다 Task.WhenAll.

샘플 코드 :

var task1 = HttpService1Async();
var task2 = HttpService2Async();

await Task.WhenAll(task1, task2)

var result1 = task1.Result;
var result2 = task2.Result;

// Use result1 and result2

이 코드는 성능면에서 첫 번째 코드보다 낫습니까? 다른 방법을 사용할 수 있습니까?



답변

Task.WhenAll 사용하면 하나의 문제는 결과를 반환하지 않는다는 것입니다.

그러나 그것은 수행 결과를 반환합니다. 그것들은 모두 공통 유형의 배열에있을 것이므로 결과를 사용하는 것이 항상 유용한 것은 아닙니다 . 결과를 원하는 배열에 해당하는 항목을 찾아서 Task잠재적으로 캐스트해야합니다. 실제 유형 이므로이 컨텍스트에서 가장 쉽고 읽기 쉬운 접근법은 아니지만 모든 작업의 ​​모든 결과를 원할 때 공통 유형은 처리하려는 유형입니다. .

결과를 가져 오려면 Task.WhenAll을 호출 한 후 task.Result를 호출 할 수 있습니다. 모든 작업이 이미 완료되어 응답을 가져와야하기 때문에 모두?

네, 그렇게 할 수 있습니다. 당신은 await그들 도 할 수 있습니다 ( await결함이있는 작업에서 예외를 풀지 Result만 집계 예외를 throw하지만 그렇지 않으면 동일합니다).

이 코드는 성능면에서 첫 번째 코드보다 낫습니까?

두 작업을 동시에 수행하는 것이 아니라 두 작업을 동시에 수행합니다. 그것이 더 나은지 나쁜지는 기본 작업이 무엇인지에 달려 있습니다. 기본 작업이 “디스크에서 파일 읽기”인 경우 디스크 헤드가 하나만 있고 주어진 시간에 한 곳에만있을 수 있으므로 병렬로 수행하는 것이 느려질 수 있습니다. 두 파일 사이를 뛰어 다니는 것은 한 파일을 읽은 다음 다른 파일을 읽는 것보다 느립니다. 반면, 작업이 “일부 네트워크 요청을 수행”하는 경우 (여기서와 같이) 응답을 기다릴 수 있기 때문에 작업이 더 빠를 수 있습니다 (최소한 특정 수의 동시 요청 수). 보류중인 다른 네트워크 요청이있을 때와 마찬가지로 다른 네트워크 컴퓨터에서도 빠르게. 당신이 그것을 알고 싶다면

다른 방법을 사용할 수 있습니까?

당신이 알고있는 당신에게하지 않는 것이 중요합니다 경우 모든 할 수 있습니다 단순히 당신이 아니라 바로 첫 번째보다 병행하고있는 모든 작업 사이에 던져진 예외를 await하지 않고 작업을 WhenAll전혀. 있는 유일한 방법은 WhenAll당신이 데 제공 AggregateException하지 않고 첫 번째 고장 난 작업을 명중 할 때 던지는 것보다, 모든 고장 난 작업에서 모든 단일 제외합니다. 다음과 같이 간단합니다.

var task1 = HttpService1Async();
var task2 = HttpService2Async();

var result1 = await task1;
var result2 = await task2;


답변

다음은 SemaphoreSlim을 사용하고 최대 병렬 처리 수준을 설정할 수있는 확장 방법입니다.

    /// <summary>
    /// Concurrently Executes async actions for each item of <see cref="IEnumerable<typeparamref name="T"/>
    /// </summary>
    /// <typeparam name="T">Type of IEnumerable</typeparam>
    /// <param name="enumerable">instance of <see cref="IEnumerable<typeparamref name="T"/>"/></param>
    /// <param name="action">an async <see cref="Action" /> to execute</param>
    /// <param name="maxDegreeOfParallelism">Optional, An integer that represents the maximum degree of parallelism,
    /// Must be grater than 0</param>
    /// <returns>A Task representing an async operation</returns>
    /// <exception cref="ArgumentOutOfRangeException">If the maxActionsToRunInParallel is less than 1</exception>
    public static async Task ForEachAsyncConcurrent<T>(
        this IEnumerable<T> enumerable,
        Func<T, Task> action,
        int? maxDegreeOfParallelism = null)
    {
        if (maxDegreeOfParallelism.HasValue)
        {
            using (var semaphoreSlim = new SemaphoreSlim(
                maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value))
            {
                var tasksWithThrottler = new List<Task>();

                foreach (var item in enumerable)
                {
                    // Increment the number of currently running tasks and wait if they are more than limit.
                    await semaphoreSlim.WaitAsync();

                    tasksWithThrottler.Add(Task.Run(async () =>
                    {
                        await action(item).ContinueWith(res =>
                        {
                            // action is completed, so decrement the number of currently running tasks
                            semaphoreSlim.Release();
                        });
                    }));
                }

                // Wait for all tasks to complete.
                await Task.WhenAll(tasksWithThrottler.ToArray());
            }
        }
        else
        {
            await Task.WhenAll(enumerable.Select(item => action(item)));
        }
    }

샘플 사용법 :

await enumerable.ForEachAsyncConcurrent(
    async item =>
    {
        await SomeAsyncMethod(item);
    },
    5);


답변

둘 중 하나를 사용할 수 있습니다

Parallel.Invoke(() =>
{
    HttpService1Async();
},
() =>
{
    HttpService2Async();
});

또는

Task task1 = Task.Run(() => HttpService1Async());
Task task2 = Task.Run(() => HttpService2Async());

//If you wish, you can wait for a particular task to return here like this:
task1.Wait();


답변