이 foreach 코드를 Parallel.ForEach로 어떻게 변환 할 수 있습니까?


180

나는 약간 혼란스러워한다 Parallel.ForEach.
무엇이며 Parallel.ForEach정확히 무엇을합니까?
MSDN 링크를 참조하지 마십시오.

다음은 간단한 예입니다.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);

foreach (string line in list_lines)
{
    //My Stuff
}

이 예제를 Parallel.ForEach어떻게 다시 작성할 수 있습니까?



1
@UjjwalManandhar Parallel클래스와 PLINQ 사용 의 차이점을 묻기 때문에 실제로는 상당히 다릅니다 .
리드 콥시

18
다른 사람들은 당신이 어떻게 다시 쓸 수 있는지에 대답했습니다. 그래서 무엇을합니까? normal과 마찬가지로 컬렉션의 각 항목에 대해 "작업"을 수행 foreach합니다. 차이점은 병렬 버전은 동시에 많은 "동작"을 수행 할 수 있다는 것입니다. 대부분의 경우 (코드를 실행하는 컴퓨터 및 사용중인 컴퓨터 등에 따라 다름) 더 빠르며 가장 중요한 이점입니다. 병렬로 수행 하면 항목이 어떤 순서 로 처리 되는지 알 수 없습니다 . 일반적인 (직렬) foreach을 사용하면 lines[0]먼저, 그 다음으로 계속되는 것이 보장 lines[1]됩니다.
Jeppe Stig Nielsen 님이

1
@JeppeStigNielsen 병렬 처리에 상당한 오버 헤드가 있기 때문에 항상 빠르지 는 않습니다 . 반복하는 컬렉션의 크기와 그 안에있는 작업에 따라 다릅니다. 올바른 방법은 Parallel.ForEach () 사용과 foreach () 사용의 차이 를 실제로 측정 하는 것입니다. 여러 번 일반 foreach ()가 더 빠릅니다.
Dave Black

3
@DaveBlack 물론입니다. 하나는해야한다 측정 은 각각의 경우에, 빠르게 또는 느리게 여부. 나는 일반적으로 병렬화를 설명하려고했습니다.
Jeppe Stig Nielsen

답변:


126
string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);
Parallel.ForEach(list_lines, line =>
{
    //Your stuff
});

6
단지 그것을 지적하고 싶었다. (OP를위한 더 많은 것) 그것이 단지 작동한다는 오도 된 생각이 없도록 List<T>;)
Reed Copsey

1
관심과 답변에 감사드립니다. HASH 목록을 사용하여 중복 항목을 제거하기 때문에 코드에서 List <string>을 사용했습니다. 일반 배열을 사용하면 중복을 쉽게 제거 할 수 없습니다 :).
SilverLight

119
원래의 게시물의 질문에 대한 설명이 없기 때문에 나는이 대답이 정답으로 표시되어 있는지 혼란 스러워요 ... "무엇 Parallel.ForEach이며 정확히 어떤 기능을 수행합니까이?"
FOSE

6
@fosb 문제는 질문 제목이 의미를 완전히 바꾸기 위해 편집되었다는 것입니다. 따라서이 답변은 더 이상 의미가 없습니다. 그럼에도 불구하고, 그것은 여전히 ​​좋지 않은 대답입니다
aw04

274

Foreach 루프 :

  • 반복은 하나씩 순차적으로 수행됩니다.
  • foreach 루프는 단일 스레드에서 실행됩니다.
  • foreach 루프는 .NET의 모든 프레임 워크에서 정의됩니다.
  • 느리게 실행되는 프로세스는 순차적으로 실행 되므로 느려질 수 있습니다.
    • 프로세스 2는 1이 완료 될 때까지 시작할 수 없습니다. 프로세스 3은 2 & 1이 완료 될 때까지 시작할 수 없습니다 ...
  • 스레딩 오버 헤드가 없으므로 빠른 프로세스 실행이 더 빨라질 수 있습니다.

Parallel.ForEach :

  • 실행은 병렬로 수행됩니다.
  • Parallel.ForEach는 여러 스레드를 사용합니다.
  • Parallel.ForEach는 .Net 4.0 이상 프레임 워크에서 정의됩니다.
  • 의 실행 속도가 느린 프로세스가 될 수 있습니다 빨리 그들이 병렬로 실행할 수있는,
    • 프로세스 1, 2 및 3 동시에 실행될 있습니다 (아래 예에서 재사용 된 스레드 참조).
  • 추가 스레딩 오버 헤드로 인해 빠른 프로세스 실행이 느려질 수 있습니다.

다음 예제는 전통적인 foreach 루프와

Parallel.ForEach () 예제

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelForEachExample
{
    class Program
    {
        static void Main()
        {
            string[] colors = {
                                  "1. Red",
                                  "2. Green",
                                  "3. Blue",
                                  "4. Yellow",
                                  "5. White",
                                  "6. Black",
                                  "7. Violet",
                                  "8. Brown",
                                  "9. Orange",
                                  "10. Pink"
                              };
            Console.WriteLine("Traditional foreach loop\n");
            //start the stopwatch for "for" loop
            var sw = Stopwatch.StartNew();
            foreach (string color in colors)
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            Console.WriteLine("foreach loop execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);
            Console.WriteLine("Using Parallel.ForEach");
            //start the stopwatch for "Parallel.ForEach"
             sw = Stopwatch.StartNew();
            Parallel.ForEach(colors, color =>
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            );
            Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", sw.Elapsed.TotalSeconds);
            Console.Read();
        }
    }
}

산출

Traditional foreach loop
1. Red, Thread Id= 10
2. Green, Thread Id= 10
3. Blue, Thread Id= 10
4. Yellow, Thread Id= 10
5. White, Thread Id= 10
6. Black, Thread Id= 10
7. Violet, Thread Id= 10
8. Brown, Thread Id= 10
9. Orange, Thread Id= 10
10. Pink, Thread Id= 10
foreach loop execution time = 0.1054376 seconds

Parallel.ForEach 예제 사용

1. Red, Thread Id= 10
3. Blue, Thread Id= 11
4. Yellow, Thread Id= 11
2. Green, Thread Id= 10
5. White, Thread Id= 12
7. Violet, Thread Id= 14
9. Orange, Thread Id= 13
6. Black, Thread Id= 11
8. Brown, Thread Id= 10
10. Pink, Thread Id= 12
Parallel.ForEach() execution time = 0.055976 seconds

63
Parallel.ForEach가 (항상) 더 빠르다는 귀하의 '클레임'에 동의하지 않습니다. 이것은 실제로 루프 내부의 작업에 대한 무거움에 달려 있습니다. 이것은 병렬화를 도입하는 것의 오버 헤드가 될 수도 있고 그렇지 않을 수도 있습니다.
Martao

1
각각의 병렬은 루프 본문에서 코드를 실행하기 위해 별도의 스레드가 설정되어 있음을 의미합니다. .NET에는이를위한 효율적인 메커니즘이 있지만 이는 상당한 오버 헤드입니다. 따라서 간단한 연산 (예 : 합 또는 곱셈)을 해야하는 경우 병렬 foreach가 더 빠르지 않아야합니다.
Martao

3
@Jignesh 이것은 좋은 측정 예조차 아니므로 이것을 전혀 언급하지 않을 것입니다. "Thread.Sleep (10);"제거 각 루프 본문에서 다시 시도하십시오.
stenly

1
@Martao가 맞습니다. 문제는 병렬 접근이 순차적보다 길 수있는 객체 잠금 오버 헤드에 있습니다.
stenly

8
@stenly 수면이 좋은 예 라고 생각합니다 . Martao가 설명했듯이 빠른 단일 반복으로 PFE를 사용하지 않을 것이므로이 답변은 반복을 느리게하고 PFE의 (올바른) 이점이 강조 표시됩니다. 나는 이것이 대답에서 설명되어야한다고 동의하지만, 대담한 "항상 빠르다"는 매우 오도됩니다.
mafu

43
string[] lines = File.ReadAllLines(txtProxyListPath.Text);

// No need for the list
// List<string> list_lines = new List<string>(lines); 

Parallel.ForEach(lines, line =>
{
    //My Stuff
});

이렇게하면 루프 내에서 행이 병렬로 구문 분석됩니다. Parallel 클래스에 대한보다 자세하고 "참조 지향적 인"소개를 원한다면 Parallel.ForEach 섹션 을 포함하는 시리즈를 TPL에 작성했습니다 .


9

큰 파일의 경우 다음 코드를 사용하십시오 (메모리가 부족합니다)

Parallel.ForEach(File.ReadLines(txtProxyListPath.Text), line => {
    //Your stuff
});

2

이 라인은 나를 위해 일했습니다.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.