2017-05-03 2 views
0

저는 비동기 프로그래밍을 처음 접했습니다. 나는 그들 중 어떤 것을 기다리기 전에 일련의 작업 (http 요청을하는)을 시작하려고한다.Task.WhenAll은 언제 열거합니까?

List<Guid> identifiers; 

//Set identifiers to what they should be 

var task = Task.WhenAll(identifiers.Select(id => _serviceConnector.GetAsync(id))); 

// Call and await another request 

await task; 

내 질문은 : 내 http 요청이 Task.WhenAll을 통해 작업 생성과 함께 시작될 예정입니까? 또는 그들이 더 아래를 기다릴 때까지 그들은 시작되지 않을 것인가? 감사!

답변

1

내 http 요청은 Task.WhenAll을 통해 작업 생성으로 시작할 수 있습니까? 또는 그들이 더 아래를 기다릴 때까지 그들은 시작되지 않을 것인가?

당신이 LINQ 쿼리를 전달하면 의미
if (tasks == null) throw new ArgumentNullException("tasks"); 
List<Task<TResult>> taskList = new List<Task<TResult>>(); 
foreach (Task<TResult> task in tasks) 
{ 
    if (task == null) throw new ArgumentException("tasks"); 
    taskList.Add(task); 
} 

,이 실행됩니다 : 당신이 작업의 순서를 열거하고 추가 처리를 위해 목록에 그들 모두를두고 IEnumerable<Task>Task.WhenAll에 통과

identifiers.Select(id => _serviceConnector.GetAsync(id)) 

하지만 Task.WhenAll 이러한 작업을 시작하는 것을 의미하지 않는다. 예 : 쿼리가 시작되지 않은 작업을 반환하는 경우 해당 작업은 실행되지 않는 상태로 유지됩니다. 예 : 작업을 생성합니다 쿼리를 다음 그러나 것은 그들을 시작되지 않습니다, 따라서 WhenAll는 모든 GetAsync(id) 방법에 따라 이러한 작업 귀하의 경우에는

var tasks = Enumerable.Range(1, 10).Select(i => new Task<int>(() => i)); 
var task = Task.WhenAll(tasks); 

기다리고 붙어 있습니다. 을 만들고 과 같은 작업을 시작하면 Task.WhenAll 호출 시작시 모든 작업이 만들어지고 시작됩니다.


TL; DR Task.WhenAll 방법 구현 세부. 위에서 언급 한 바와 같이, 모든 주어진 작업을 잡고 (IEnumerable을 인수는 목록에 모든 작업을두고)하고이 작업이 ITaskCompletionAction를 구현 볼 수있는 유형 WhenAllPromise<T>

private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction 

의 새 작업을 만듭니다. 이 인터페이스는 작업에 완료 작업을 추가하는 데 사용되는 내부 인터페이스입니다 (간단한 작업이기 때문에 계속 작업의 간단한 버전 임). 이 인터페이스는 작업이 완료 될 때 호출되어야하는 단일 메서드 Invoke(Task)을 정의합니다.

internal void AddCompletionAction(ITaskCompletionAction action) 

이제 다시 클래스 WhenAllPromise<T>에 : Task 다음 경량의 연속성을 추가 허용하는 내부 메소드가 있습니다. 초기화하는 동안

private readonly Task<T>[] m_tasks; 
private int m_count; 

이 클래스를 저장 필드 배열의 모든 주어진 작업 카운터를 초기화하고, 중 이미 완료된 작업에 대한 지속을 호출 또는 완료 작업 작업 자체를 추가합니다 : 그것은 두 개의 필드가

m_tasks = tasks; 
m_count = tasks.Length; 

foreach (var task in tasks) 
{ 
    if (task.IsCompleted) this.Invoke(task); // short-circuit 
    else task.AddCompletionAction(this); // simple completion action 
} 

을 그게 전부 야. 작업은 WhenAllPromise 클래스에 의해 시작되지 않습니다. 작업이 완료 될 때 호출되는 콜백 동작 만 사용합니다. 콜백 동작에서 일부 작업이 완료 될 때마다 m_count가 감소하여 모든 작업이 완료되고 결과를 얻을 수 있습니다.

1

WhenAll 즉시 열거 가능한 인수를 나타냅니다. 따라서 모든 작업은 WhenAll이 반환 할 때 시작됩니다.

이것에 대해 생각해 보면 이해할 수 있습니다. WhenAll은 대기중인 작업 수를 알아야하므로 자체 작업이 언제 완료되는지를 알 수 있습니다. 또한 각 하위 작업이 완료 될 때 알림을 받도록 각 작업에 연결해야합니다. 이 작업을 할 다른 시간은 없습니다. 그것은 이어야하고 반환하기 전에 알림을 설정해야합니다.