WaitAll 대 WhenAll


답변:


504

Task.WaitAll 모든 것이 완료 될 때까지 현재 스레드를 차단합니다.

Task.WhenAll모든 것이 완료 될 때까지 기다리는 동작을 나타내는 작업 을 반환합니다 .

즉, 비동기 메서드에서 다음을 사용할 수 있습니다.

await Task.WhenAll(tasks);

... 모든 것이 완료되면 메소드가 계속된다는 것을 의미하지만 그 시간까지 스레드를 묶지 않습니다.


2
많이 읽은 후에 비동기는 스레드 블로그
Vince Panuccio

7
@Vince : "스레드와 관련이 없음"은 과장된 것으로 생각하고 비동기 작업이 스레드와 상호 작용하는 방식을 이해하는 것이 중요합니다.
Jon Skeet

6
@KevinBui : 아니, 그것은 안 차단 -는 것을 기다리고 에 의해 반환 된 작업을 WhenAll하지만, 그 스레드를 차단 같은 아니에요.
Jon Skeet

1
@JonSkeet 아마도이 둘의 정확한 구별은 너무 미묘합니다. 당신은 저 (그리고 아마도 우리의 나머지)에게 차이를 분명히 할 수있는 어떤 언급을 할 수 있습니까?
CatShoes

125
@ CatShoes : 실제로는 아닙니다-이미 설명했듯이 이미 설명했습니다. 나는 비유를 줄 수있을 것 같아요-테이크 아웃 주문과 도착 대기 시간, 테이크 아웃 주문, 다른 일을 한 다음 택배가 도착했을 때 문을 여는 것의 차이점과 같습니다.
Jon Skeet

51

JonSkeet의 답변은 차이점을 일반적으로 훌륭한 방법으로 설명하지만 또 다른 차이점은 예외 처리 입니다.

Task.WaitAll이 발생 AggregateException하는 작업 중 하나를 던져 모든 던져 예외를 검사 할 수 있습니다 때. 의 awaitawait Task.WhenAll포장을 풀고 AggregateException첫 번째 예외 만 '반환'합니다.

아래 프로그램 await Task.WhenAll(taskArray)이 출력으로 실행될 때 다음과 같습니다.

19/11/2016 12:18:37 AM: Task 1 started
19/11/2016 12:18:37 AM: Task 3 started
19/11/2016 12:18:37 AM: Task 2 started
Caught Exception in Main at 19/11/2016 12:18:40 AM: Task 1 throwing at 19/11/2016 12:18:38 AM
Done.

아래의 프로그램 Task.WaitAll(taskArray)이 출력으로 실행될 때 다음과 같습니다.

19/11/2016 12:19:29 AM: Task 1 started
19/11/2016 12:19:29 AM: Task 2 started
19/11/2016 12:19:29 AM: Task 3 started
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 1 throwing at 19/11/2016 12:19:30 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 2 throwing at 19/11/2016 12:19:31 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 3 throwing at 19/11/2016 12:19:32 AM
Done.

프로그램:

class MyAmazingProgram
{
    public class CustomException : Exception
    {
        public CustomException(String message) : base(message)
        { }
    }

    static void WaitAndThrow(int id, int waitInMs)
    {
        Console.WriteLine($"{DateTime.UtcNow}: Task {id} started");

        Thread.Sleep(waitInMs);
        throw new CustomException($"Task {id} throwing at {DateTime.UtcNow}");
    }

    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            await MyAmazingMethodAsync();
        }).Wait();

    }

    static async Task MyAmazingMethodAsync()
    {
        try
        {
            Task[] taskArray = { Task.Factory.StartNew(() => WaitAndThrow(1, 1000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(2, 2000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(3, 3000)) };

            Task.WaitAll(taskArray);
            //await Task.WhenAll(taskArray);
            Console.WriteLine("This isn't going to happen");
        }
        catch (AggregateException ex)
        {
            foreach (var inner in ex.InnerExceptions)
            {
                Console.WriteLine($"Caught AggregateException in Main at {DateTime.UtcNow}: " + inner.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Caught Exception in Main at {DateTime.UtcNow}: " + ex.Message);
        }
        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

13
가장 큰 실제 차이점은 예외 처리입니다. 정말? 그것이 실제로 가장 큰 차이는 아니기 때문입니다. 가장 큰 실질적인 차이는 비동기 및 비 차단입니다. 이것은 예외를 처리하는 방법보다 훨씬 중요합니다.
Liam

5
이것을 지적 해 주셔서 감사합니다. 이 설명은 현재 작업중인 시나리오에서 유용했습니다. 아마도 "가장 큰 실질적인 차이"는 아니지만 분명히 좋은 선택입니다.
Urk

실질적인 차이가 가장 큰 예외 처리는 await t1; await t2; await t3;vsawait Task.WhenAll(t1,t2,t3);
frostshoxx

1
이 예외 동작이 여기에있는 문서와 모순되지 않습니까 ( docs.microsoft.com/en-us/dotnet/api/… ) "제공된 작업 중 하나라도 오류 상태에서 완료되면 반환 된 작업도 오류 상태에서 완료됩니다 "예외에는 제공된 각 작업에서 래핑되지 않은 예외 집합이 포함됩니다."
Dasith Wijes

1
나는 이것이 await두 방법의 차이점이 아닌 의 인공물이라고 생각 합니다. 둘 다 AggregateException직접 또는 속성 ( Task.Exception속성)을 통해 던지는를 전파합니다 .
Theodor Zoulias

20

차이점의 예로-작업이있는 경우 UI 스레드로 작업을 수행하면 (예 : 스토리 보드에서 애니메이션을 나타내는 작업) Task.WaitAll()UI 스레드가 차단되고 UI가 업데이트되지 않습니다. 사용 await Task.WhenAll()하면 UI 스레드가 차단되지 않고 UI가 업데이트됩니다.


7

그들은 무엇을합니까:

  • 내부적으로 모두 같은 일을합니다.

차이점이 뭐야:

  • WaitAll 은 차단 통화입니다
  • WhenAll - not- 코드가 계속 실행됩니다

다음과 같은 경우에 사용하십시오.

  • 결과가 없으면 계속할 수없는 경우 모두 대기
  • 언제 알림 만 받고 차단되지 않는 경우

1
@MartinRhodes하지만 당신은 즉시 기다리고 있지만, 일부 다른 작업을 계속하지 않으면 어떻게 다음은 그것을 기다리고? WaitAll내가 이해 한대로 그 가능성은 없습니다 .
Jeppe

@Jeppe 당신이 다른 일 을 Task.WaitAll 한 후에 전화를 달리지 않겠습니까 ? 당신의 작업을 시작한 직후에 전화하는 대신에.
PL
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.