제가 아는 선에서 조금 살을 붙이면 tasks의 평가는 await하는 순간이 아니라 tasks 객체를 처음 사용하게 될 때 됩니다.
그러므로 실제 tasks의 평가는 foreach문의 tasks입니다.
적어주신 코드를 보면 평가된 tasks를 하나씩 await하고 계셔서 순차 실행이 되는 것이고
foreach문 안에서 await를 하지 않으면 말씀하신 ToList()나 ToArray()로 즉시평가하는 것처럼 동작합니다.
var tasks = behaviors.Select(x => x.ExecuteAsync());
foreach (var task in tasks) // tasks의 평가는 여기서 되고
{
// 각각의 tasks를 await하지 않으면 마치 병렬로 실행 된 것처럼 결과가 나온다.
//await task;
}
그리고 지연평가가 좋은 것이긴 한데 멀티 쓰레드 작업을 하다보면 각 쓰레드끼리 아직 평가되지 않은 IEnumerable을 공유하게 되면서 원하는 결과가 나오지 않을 때도 있습니다. 이럴 때는 말씀하신 것 처럼 linq작성 후 즉시 ToList()등으로 평가해서 사용해야합니다.
Select.cs 코드를 보시면 selector가 (x, i) => x.RunAsync(i) 인데요.
selector가 언제 실행되시는지를 봐야 합니다.
같은 파일의 IEnumerableSelectIterator를 보시면 MoveNext함수에서 _selector를 호출하는 것을 볼 수 있습니다.
누가 언제 MoveNext를 호출하는가?
이제 foreach의 구현을 볼 차례입니다.
그것은 직접…ㅋㅋ (저는 여기까지만 보겠습니다.)