Bagaimana saya bisa mengkonversi kode foreach ini ke Parallel.ForEach?

180

Saya sedikit bingung Parallel.ForEach.
Apa itu Parallel.ForEachdan apa fungsinya?
Tolong jangan referensi tautan MSDN.

Berikut ini contoh sederhana:

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

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

Bagaimana saya bisa menulis ulang contoh ini dengan Parallel.ForEach?

SilverLight
sumber
Ini mungkin telah dijawab di sini stackoverflow.com/questions/3789998/…
Ujjwal Manandhar
1
@UjjwalManandhar Itu sebenarnya sangat berbeda, karena menanyakan tentang perbedaan antara Parallelkelas dan menggunakan PLINQ.
Reed Copsey
18
Orang lain telah menjawab bagaimana Anda dapat menulis ulang. Jadi apa fungsinya? Itu melakukan "tindakan" pada setiap item dalam koleksi, seperti biasa foreach. Perbedaannya adalah bahwa versi paralel dapat melakukan banyak "tindakan" pada saat yang sama. Dalam kebanyakan kasus (tergantung pada komputer apa yang menjalankan kode, dan seberapa sibuknya, dan hal-hal lain) akan lebih cepat, dan itulah keuntungan yang paling penting. Perhatikan bahwa ketika Anda melakukannya secara paralel, Anda tidak dapat mengetahui urutan barang yang diproses. Dengan biasa (serial) foreach, Anda dijamin yang lines[0]datang pertama, lalu lines[1], dan sebagainya.
Jeppe Stig Nielsen
1
@JeppeStigNielsen Ini akan tidak selalu lebih cepat karena ada overhead yang signifikan dengan membuat hal-hal paralel. Itu tergantung pada ukuran koleksi yang Anda iterasi dan tindakan di dalamnya. Hal yang benar untuk dilakukan adalah benar-benar mengukur perbedaan antara menggunakan Parallel.ForEach () dan menggunakan foreach (). Banyak kali foreach normal () lebih cepat.
Dave Black
3
@ DaveBlack Tentu. Seseorang harus mengukur apakah lebih cepat atau lebih lambat, dalam setiap kasus. Saya hanya mencoba menggambarkan paralelisasi secara umum.
Jeppe Stig Nielsen

Jawaban:

126
string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);
Parallel.ForEach(list_lines, line =>
{
    //Your stuff
});
LB
sumber
6
Hanya ingin menunjukkannya (lebih untuk OP) sehingga tidak ada pemikiran yang salah bahwa itu hanya berhasil List<T>;)
Reed Copsey
1
terima kasih atas perhatian dan jawabannya. saya menggunakan Daftar <string> dalam kode saya karena menghapus item duplikat menggunakan daftar HASH. dengan array reguler kita tidak bisa menghapus duplikat dengan mudah :).
SilverLight
119
Saya bingung bahwa jawaban ini ditandai sebagai jawaban yang benar, karena tidak ada penjelasan untuk pertanyaan posting asli "Apa itu Paralel. Untuk setiap bagian dan apa fungsinya?" ...
fose
6
@fosb Masalahnya adalah judul pertanyaan telah diedit untuk sepenuhnya mengubah artinya ... jadi jawaban ini tidak lagi masuk akal. Karena itu, itu masih jawaban yang buruk
aw04
274

Loop depan:

  • Iterasi berlangsung berurutan, satu per satu
  • foreach loop dijalankan dari satu Thread.
  • foreach loop didefinisikan dalam setiap framework .NET
  • Eksekusi dari proses yang lambat bisa lebih lambat , karena mereka berjalan secara seri
    • Proses 2 tidak dapat dimulai sampai 1 selesai. Proses 3 tidak dapat dimulai sampai 2 & 1 selesai ...
  • Eksekusi proses cepat bisa lebih cepat , karena tidak ada overhead threading

Paralel. Setiap Pertemuan:

  • Eksekusi dilakukan secara paralel.
  • Paralel. FOREach menggunakan beberapa Thread.
  • Parallel.ForEach didefinisikan dalam .Net 4.0 dan kerangka kerja di atas.
  • Eksekusi dari proses yang lambat bisa lebih cepat , karena dapat dijalankan secara paralel
    • Proses 1, 2, & 3 dapat berjalan secara bersamaan (lihat utas yang digunakan kembali misalnya, di bawah)
  • Eksekusi proses cepat bisa lebih lambat , karena overhead threading tambahan

Contoh berikut dengan jelas menunjukkan perbedaan antara loop foreach tradisional dan

Parallel.ForEach () Contoh

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();
        }
    }
}

Keluaran

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

Menggunakan Parallel. FOREach misalnya

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
Jignesh.Raj
sumber
63
Saya benar-benar tidak setuju dengan 'klaim' Anda bahwa Paralel. FOREach (selalu) lebih cepat. Ini sangat tergantung pada beratnya operasi di dalam loop. Ini mungkin layak atau tidak sebanding dengan memperkenalkan paralellisme.
Martao
1
Nah, paralel untuk masing-masing berarti bahwa utas terpisah diatur untuk mengeksekusi kode dalam tubuh loop. Meskipun .NET memang memiliki mekanisme yang efisien untuk melakukan ini, ini adalah overhead yang cukup besar. Jadi, jika Anda hanya perlu operasi sederhana (mis. Penjumlahan atau perkalian), pendahuluan sejajar tidak harus lebih cepat.
Martao
3
@ Jignesh ini bahkan bukan contoh pengukuran yang baik jadi saya tidak akan merujuk ini sama sekali. Hapus "Utas. Tidur (10);" dari setiap loop body dan coba lagi.
stenly
1
@ Martao benar, masalahnya adalah dengan overhead penguncian objek di mana pendekatan paralel mungkin lebih lama daripada berurutan.
stenly
8
@stenly Saya pikir Tidur adalah alasan mengapa itu adalah contoh yang baik . Anda tidak akan menggunakan PFE dengan iterasi tunggal cepat (seperti yang dijelaskan Martao) - jadi jawaban ini membuat iterasi lambat, dan keunggulan (benar) PFE disorot. Saya setuju bahwa ini perlu dijelaskan dalam jawaban, huruf tebal "selalu lebih cepat" sangat menyesatkan.
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
});

Ini akan menyebabkan garis diurai secara paralel, di dalam loop. Jika Anda ingin pengantar yang lebih rinci, kurang "referensi" ke kelas Paralel, saya menulis seri pada TPL yang mencakup bagian tentang Paralel . Untuk Setiap.

Reed Copsey
sumber
9

Untuk file besar, gunakan kode berikut (Anda kurang haus memori)

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

Garis-garis ini bekerja untuk saya.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
Pangeran Prasad
sumber