ให้รหัสนี้:
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
DoSomething(someString);
});
เธรดทั้งหมด 1,000 เธรดจะเกิดเกือบพร้อมกันหรือไม่?
ให้รหัสนี้:
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
DoSomething(someString);
});
เธรดทั้งหมด 1,000 เธรดจะเกิดเกือบพร้อมกันหรือไม่?
คำตอบ:
ไม่มันจะไม่เริ่ม 1,000 เธรดใช่มันจะ จำกัด จำนวนเธรดที่ใช้ Parallel Extensions ใช้จำนวนคอร์ที่เหมาะสมโดยพิจารณาจากจำนวนคอร์ที่คุณมีอยู่จริงและจำนวนที่ยุ่งอยู่แล้ว จะจัดสรรงานสำหรับแต่ละคอร์จากนั้นใช้เทคนิคที่เรียกว่าการขโมยงานเพื่อให้แต่ละเธรดประมวลผลคิวของตัวเองได้อย่างมีประสิทธิภาพและจำเป็นต้องทำการเข้าถึงข้ามเธรดที่มีราคาแพงเมื่อจำเป็นจริงๆ
มีลักษณะที่เป็นบล็อก PFX ทีมสำหรับการโหลดของข้อมูลเกี่ยวกับวิธีการที่จะจัดสรรงานและทุกชนิดของหัวข้ออื่น ๆ
โปรดทราบว่าในบางกรณีคุณสามารถระบุระดับความขนานที่ต้องการได้เช่นกัน
บนเครื่องแกนเดียว ... Parallel ForEach พาร์ติชัน (ชิ้นส่วน) ของคอลเล็กชันมันทำงานระหว่างเธรดจำนวนหนึ่ง แต่จำนวนนั้นคำนวณจากอัลกอริทึมที่คำนึงถึงและดูเหมือนจะตรวจสอบงานที่ทำโดย เธรดที่จัดสรรให้กับ ForEach ดังนั้นหากส่วนเนื้อหาของ ForEach เรียกใช้ฟังก์ชัน IO-bound / block ที่รันเป็นเวลานานซึ่งจะปล่อยให้เธรดรออยู่รอบ ๆ อัลกอริทึมจะสร้างเธรดมากขึ้นและแบ่งพาร์ติชันระหว่างคอลเล็กชันใหม่ หากเธรดเสร็จสิ้นอย่างรวดเร็วและไม่บล็อกเธรด IO เช่นเพียงแค่คำนวณตัวเลขบางตัวอัลกอริทึมจะทางลาดขึ้นไป (หรืออันที่จริงลง) จำนวนกระทู้ไปยังจุดที่ขั้นตอนวิธีการพิจารณาที่เหมาะสมสำหรับการส่งผ่าน (ที่เวลาเสร็จสิ้นเฉลี่ยของแต่ละซ้ำ)
โดยทั่วไปเธรดพูลที่อยู่เบื้องหลังฟังก์ชันไลบรารี Parallel ต่างๆทั้งหมดจะคำนวณจำนวนเธรดที่เหมาะสมที่จะใช้ จำนวนคอร์ตัวประมวลผลฟิสิคัลเป็นเพียงส่วนหนึ่งของสมการ ไม่มีความสัมพันธ์แบบหนึ่งต่อหนึ่งง่ายๆระหว่างจำนวนคอร์และจำนวนเธรดที่เกิด
ฉันไม่พบเอกสารเกี่ยวกับการยกเลิกและการจัดการเธรดการซิงโครไนซ์ที่มีประโยชน์มาก หวังว่า MS สามารถจัดหาตัวอย่างที่ดีกว่าใน MSDN ได้
อย่าลืมว่าโค้ดของร่างกายจะต้องถูกเขียนขึ้นเพื่อให้ทำงานบนเธรดหลาย ๆ เธรดพร้อมกับการพิจารณาความปลอดภัยของเธรดตามปกติเฟรมเวิร์กไม่ได้ทำให้ปัจจัยนั้นเป็นนามธรรม ...
ทำงานโดยใช้จำนวนเธรดที่เหมาะสมตามจำนวนโปรเซสเซอร์ / คอร์ พวกมันจะไม่วางไข่ทั้งหมดในครั้งเดียว
ดูแบบขนานสำหรับใช้หนึ่งงานต่อการวนซ้ำหรือไม่ สำหรับแนวคิด "แบบจำลองทางจิต" ที่จะใช้ อย่างไรก็ตามผู้เขียนระบุว่า "ในตอนท้ายของวันสิ่งสำคัญคือต้องจำไว้ว่ารายละเอียดการใช้งานอาจเปลี่ยนแปลงได้ตลอดเวลา"
คำถามที่ดี ในตัวอย่างของคุณระดับการขนานนั้นค่อนข้างต่ำแม้ในโปรเซสเซอร์ Quad Core แต่ด้วยการรอระดับการขนานจะค่อนข้างสูง
// Max concurrency: 5
[Test]
public void Memory_Operations()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
monitor.Add(monitor.Count);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
ตอนนี้ดูว่าจะเกิดอะไรขึ้นเมื่อมีการเพิ่มการดำเนินการรอเพื่อจำลองคำขอ HTTP
// Max concurrency: 34
[Test]
public void Waiting_Operations()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(1000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
ฉันยังไม่ได้ทำการเปลี่ยนแปลงใด ๆ และระดับของการทำงานพร้อมกัน / การขนานกันได้เพิ่มขึ้นอย่างมาก เห็นพ้องสามารถมีขีด จำกัด ParallelOptions.MaxDegreeOfParallelism
ของเพิ่มขึ้นด้วย
// Max concurrency: 43
[Test]
public void Test()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(1000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
// Max concurrency: 391
[Test]
public void Test()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(100000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
ผม reccommend ParallelOptions.MaxDegreeOfParallelism
การตั้งค่า ไม่จำเป็นต้องเพิ่มจำนวนเธรดที่ใช้งาน แต่จะช่วยให้มั่นใจได้ว่าคุณจะเริ่มเธรดตามจำนวนที่เหมาะสมเท่านั้นซึ่งดูเหมือนว่าคุณจะกังวล
สุดท้ายนี้เพื่อตอบคำถามของคุณคุณจะไม่ได้รับชุดข้อความทั้งหมดเพื่อเริ่มต้นพร้อมกัน ใช้ ParallelInvoke หากคุณต้องการเรียกใช้แบบขนานอย่างสมบูรณ์แบบเช่นการทดสอบสภาพการแข่งขัน
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623368346
// 636462943623368346
// 636462943623373351
// 636462943623393364
// 636462943623393364
[Test]
public void Test()
{
ConcurrentBag<string> monitor = new ConcurrentBag<string>();
ConcurrentBag<string> monitorOut = new ConcurrentBag<string>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(DateTime.UtcNow.Ticks.ToString());
monitor.TryTake(out string result);
monitorOut.Add(result);
});
var startTimes = monitorOut.OrderBy(x => x.ToString()).ToList();
Console.WriteLine(string.Join(Environment.NewLine, startTimes.Take(10)));
}