Parallel.ForEach vs Task.Run 및 Task.WhenAll
Parallel.ForEach 또는 Task.Run ()을 사용하여 일련의 작업을 비동기 적으로 시작하는 것의 차이점은 무엇입니까?
버전 1 :
List<string> strings = new List<string> { "s1", "s2", "s3" };
Parallel.ForEach(strings, s =>
{
DoSomething(s);
});
버전 2 :
List<string> strings = new List<string> { "s1", "s2", "s3" };
List<Task> Tasks = new List<Task>();
foreach (var s in strings)
{
Tasks.Add(Task.Run(() => DoSomething(s)));
}
await Task.WhenAll(Tasks);
이 경우 두 번째 방법은 작업을 차단하는 대신 비동기 적으로 작업을 기다립니다.
그러나 Task.Run
loop- With에서 사용하는 데에는 단점이 있으며 Parallel.ForEach
, Partitioner
필요 이상으로 더 많은 작업을 수행하지 않기 위해 만들어집니다. Task.Run
이 작업을 수행하는 동안 항상 항목 당 하나의 작업을 수행하지만 Parallel
클래스 배치는 작동하므로 전체 작업 항목보다 적은 작업을 생성합니다. 이는 특히 루프 본체에 품목 당 적은 양의 작업이있는 경우 전체 성능을 크게 향상시킬 수 있습니다.
이 경우 다음과 같이 작성하여 두 옵션을 결합 할 수 있습니다.
await Task.Run(() => Parallel.ForEach(strings, s =>
{
DoSomething(s);
}));
이 짧은 형식으로 작성 될 수도 있습니다.
await Task.Run(() => Parallel.ForEach(strings, DoSomething));
첫 번째 버전은 호출 스레드를 동 기적으로 차단하고 일부 작업을 실행합니다.
UI 스레드 인 경우 UI가 고정됩니다.
두 번째 버전은 스레드 풀에서 작업을 비동기 적으로 실행하고 완료 될 때까지 호출 스레드를 해제합니다.
사용 된 스케줄링 알고리즘에도 차이가 있습니다.
두 번째 예는 다음과 같이 단축 될 수 있습니다.
await Task.WhenAll(strings.Select(s => Task.Run(() => DoSomething(s)));
읽기가 더 쉬워 졌기 때문에이 작업을 마쳤습니다.
List<Task> x = new List<Task>();
foreach(var s in myCollectionOfObject)
{
// Note there is no await here. Just collection the Tasks
x.Add(s.DoSomethingAsync());
}
await Task.WhenAll(x);
Parallel.ForEach가 부적절하게 사용되는 것을 보았습니다.이 질문의 예가 도움이 될 것이라고 생각했습니다.
콘솔 앱에서 아래 코드를 실행하면 Parallel.ForEach에서 실행 된 작업이 호출 스레드를 차단하지 않는 방법을 볼 수 있습니다. 결과에 신경 쓰지 않으면 (긍정적이거나 부정적이지만) 결과가 필요하면 Task.WhenAll을 사용해야합니다.
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ParrellelEachExample
{
class Program
{
static void Main(string[] args)
{
var indexes = new int[] { 1, 2, 3 };
RunExample((prefix) => Parallel.ForEach(indexes, (i) => DoSomethingAsync(i, prefix)),
"Parallel.Foreach");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("*You'll notice the tasks haven't run yet, because the main thread was not blocked*");
Console.WriteLine("Press any key to start the next example...");
Console.ReadKey();
RunExample((prefix) => Task.WhenAll(indexes.Select(i => DoSomethingAsync(i, prefix)).ToArray()).Wait(),
"Task.WhenAll");
Console.WriteLine("All tasks are done. Press any key to close...");
Console.ReadKey();
}
static void RunExample(Action<string> action, string prefix)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine($"{Environment.NewLine}Starting '{prefix}'...");
action(prefix);
Console.WriteLine($"{Environment.NewLine}Finished '{prefix}'{Environment.NewLine}");
}
static async Task DoSomethingAsync(int i, string prefix)
{
await Task.Delay(i * 1000);
Console.WriteLine($"Finished: {prefix}[{i}]");
}
}
}
결과는 다음과 같습니다.
결론:
작업에 Parallel.ForEach를 사용하면 호출 스레드가 차단되지 않습니다. 결과가 마음에 들면 작업을 기다리십시오.
~ 건배
참고 URL : https://stackoverflow.com/questions/19102966/parallel-foreach-vs-task-run-and-task-whenall
'Programming' 카테고리의 다른 글
수동 이벤트 리스너 란 무엇입니까? (0) | 2020.06.21 |
---|---|
이클립스 자동 완성 (Juno의 퍼센트 부호) (0) | 2020.06.21 |
이상한 AQDefaultDevice 로깅 (0) | 2020.06.21 |
국제화는 JavaScript에서 어떻게 작동합니까? (0) | 2020.06.21 |
java 8 ZonedDateTime과 OffsetDateTime의 차이점은 무엇입니까? (0) | 2020.06.21 |