เป้าหมาย
เป้าหมายคือการคำนวณรูปร่างโพลีฟอร์มที่เป็นไปได้ทั้งหมดของจำนวนกำลังสองที่กำหนด เนื่องจากนี่เป็นการคำนวณที่หนักมากสำหรับจำนวนที่มากขึ้น ฉันจึงต้องการใช้หลายคอร์ที่คอมพิวเตอร์ของฉันมี
ปัญหา
ฉันทำให้ปัญหาง่ายต่อการอธิบายและทดสอบโดยการสร้างสถานการณ์ต่อไปนี้:
1) for each value of 2, 3, 5, and 7:
2) find all multiples (up to a certain value) and add them to the same List
3) remove all duplicates from said list
ในโปรแกรมสุดท้ายของฉันขั้นตอนที่ 2 นั้นกว้างใหญ่และหนักกว่ามาก ดังนั้นฉันจึงต้องการแบ่งงานที่สองออกเป็นค่าต่างๆ มากมายเท่าใดก็ได้ที่ฉันต้องการตรวจสอบตามค่าของขั้นตอนที่ 1
สิ่งที่ฉันพยายาม
ฉันสร้างแอป winforms ด้วย C# Core พร้อมปุ่ม 5 ปุ่ม ลองใช้ความคล้ายคลึงกันในรูปแบบต่างๆ ที่ฉันพบที่นี่บน Stackoverflow และที่อื่นๆ บนอินเทอร์เน็ต:
นี่คือโค้ด (ซึ่งดูเหมือนมาก แต่เป็นเพียงแนวคิดเดียวกัน 5 รูปแบบ) พวกเขาทั้งหมดให้การนับเพื่อตรวจสอบว่าได้ผลลัพธ์เดียวกันหรือไม่ + ใช้เวลานานแค่ไหน:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Parallelism
{
public partial class Form1 : Form
{
private readonly int Repeat = 10000000;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
List<int> output = new List<int>();
foreach (int x in new int[] { 2, 3, 5, 7 })
{
for (int i = 0; i < Repeat; i++)
{
output.Add(x * i);
}
}
output = output.Distinct().ToList();
watch.Stop();
(sender as Button).Text += $", c:{output.Count} - {watch.ElapsedMilliseconds}ms";
}
private void button2_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
ConcurrentBag<int> output = new ConcurrentBag<int>();
Task task = Task.WhenAll(
Task.Run(() => button2_Calculation(2, output)),
Task.Run(() => button2_Calculation(3, output)),
Task.Run(() => button2_Calculation(5, output)),
Task.Run(() => button2_Calculation(7, output))
);
task.Wait();
HashSet<int> output2 = new HashSet<int>(output);
watch.Stop();
(sender as Button).Text += $", c:{output2.Count} - {watch.ElapsedMilliseconds}ms";
}
private void button2_Calculation(int x, ConcurrentBag<int> output)
{
for (int i = 0; i < Repeat; i++)
{
output.Add(x * i);
}
}
private void button3_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
List<int> output = new List<int>();
foreach (int x in (new int[] { 2, 3, 5, 7 }).AsParallel())
{
for (int i = 0; i < Repeat; i++)
{
output.Add(x * i);
}
}
output = output.Distinct().ToList();
watch.Stop();
(sender as Button).Text += $", c:{output.Count} - {watch.ElapsedMilliseconds}ms";
}
private void button4_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
ConcurrentBag<int> output = new ConcurrentBag<int>();
Dictionary<int, Task> runningTasks = new Dictionary<int, Task>();
foreach (int x in new int[] { 2, 3, 5, 7 })
{
int value = x;
runningTasks.Add(x, Task.Factory.StartNew(() => button2_Calculation(value, output)));
}
foreach (Task t in runningTasks.Select(c => c.Value))
t.Wait();
HashSet<int> output2 = new HashSet<int>(output);
watch.Stop();
(sender as Button).Text += $", c:{output2.Count} - {watch.ElapsedMilliseconds}ms";
}
private void button5_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
ConcurrentBag<int> output = new ConcurrentBag<int>();
Parallel.ForEach(new int[] { 2, 3, 5, 7 }, x => button5_Calculation(x, output));
HashSet<int> output2 = new HashSet<int>(output);
watch.Stop();
(sender as Button).Text += $", c:{output2.Count} - {watch.ElapsedMilliseconds}ms";
}
private void button5_Calculation(int x, ConcurrentBag<int> output)
{
for (int i = 0; i < Repeat; i++)
output.Add(x * i);
}
}
}
ผลลัพธ์จนถึงตอนนี้
จนถึงขณะนี้วิธีการข้างต้นทั้งหมดส่งผลให้มีระยะเวลาใกล้เคียงกันระหว่าง 1 วินาที - 1.5 วินาที จริงๆ แล้ว บางครั้งการประมวลผลแบบอนุกรมปกติดูเหมือนจะเร็วกว่ามาก สิ่งนี้เป็นไปได้อย่างไร? ฉันคาดหวังว่าด้วย 8 คอร์ (16 คอร์เสมือน) ที่การแยกงานจะส่งผลให้ความเร็วโดยรวมเร็วขึ้น
ความช่วยเหลือใด ๆ ที่ชื่นชมอย่างมาก!
อนาคต
หลังจากเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการใช้งานการทำงานแบบขนานอย่างเหมาะสม ฉันคาดหวังว่าจะดำเนินการคำนวณทั้งหมดบนเธรดอื่น / Async เพื่อให้ GUI ยังคงตอบสนอง
แก้ไข:
ตอบกลับ @ Pac0: นี่คือการดำเนินการตามคำแนะนำของคุณ ดูเหมือนจะไม่มีความแตกต่างมากนัก:
private void button6_Click(object sender, EventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
ConcurrentBag<HashSet<int>> bag = new ConcurrentBag<HashSet<int>>();
var output = Parallel.ForEach(new int[] { 2, 3, 5, 7 }, x =>
{
HashSet<int> temp = new HashSet<int>();
for (int i = 0; i < Repeat; i++)
temp.Add(x * i);
bag.Add(temp);
});
HashSet<int> output2 = new HashSet<int>();
foreach (var hash in bag)
output2.UnionWith(hash);
watch.Stop();
(sender as Button).Text += $", c:{output2.Count} - {watch.ElapsedMilliseconds}ms";
}
Repeat = 100000000
แล้วดูผลลัพธ์ได้หรือไม่ - person Sowmyadhar Gourishetty   schedule 20.08.2020HashSet
ต่อการคำนวณแบบขนาน จากนั้นเมื่อทั้งหมดเสร็จสิ้น ให้ทำ Union of the hashset (ซึ่งจะดูแลรายการซ้ำ) - person Pac0   schedule 20.08.2020for
ลูป:for (int i = 0; i < Repeat; i++)
คุณยืนยันได้อย่างไรว่ามีปัญหาเกิดขึ้น และไม่ใช่กับโค้ดที่จะลบรายการที่ซ้ำกัน - person Joshua Robinson   schedule 20.08.2020