เมื่อการประมวลผลแบบขนานช่วยได้
ปัจจัยด้านปริมาณงานและขนาดข้อมูล
เมื่อการประมวลผลแบบขนานช่วยได้ เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
การทำงานแบบ parallel มีต้นทุน
การทำงานแบบ parallel เพิ่มต้นทุนแฝงจากการแบ่งข้อมูล การส่งงาน และการรวมผลลัพธ์ จะคุ้มค่าก็ต่อเมื่อต้นทุนนี้น้อยกว่าเวลาที่ประหยัดได้
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long sum = IntStream.rangeClosed(1, 10_000_000)
.parallel()
.asLongStream()
.sum();
System.out.println(sum);
}
}ปัจจัยที่ 1: ขนาดข้อมูล (N)
N ที่มีขนาดใหญ่ช่วยเฉลี่ยต้นทุนแฝงคงที่ของการทำงานแบบ parallel แนวทางคร่าว ๆ คือควรมีองค์ประกอบหลายหมื่นรายการก่อนที่การทำงานแบบ parallel จะคุ้มค่า
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long count = IntStream.rangeClosed(1, 5_000_000)
.parallel()
.filter(n -> n % 7 == 0)
.count();
System.out.println(count);
}
}ปัจจัยที่ 2: งานต่อองค์ประกอบ (Q)
ต้นทุน Q ของการประมวลผลแต่ละองค์ประกอบมีความสำคัญ งานต่อองค์ประกอบที่ใช้ทรัพยากรมาก เช่น การคำนวณหนัก จะได้ประโยชน์จากการทำงานแบบ parallel แม้ N จะมีขนาดเล็กกว่า
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long primes = IntStream.rangeClosed(2, 200_000)
.parallel()
.filter(Main::isPrime)
.count();
System.out.println(primes);
}
static boolean isPrime(int n) {
for (int i = 2; (long) i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
}แนวคิด N คูณ Q
ให้คิดว่างานที่มีประโยชน์ทั้งหมดคือ N x Q ยิ่งผลคูณนี้มีค่ามาก การทำงานแบบ parallel ก็ยิ่งช่วยได้มาก N ที่เล็กมากหรือ Q ที่แทบไม่มีงานมักไม่คุ้มที่จะใช้
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
double sum = IntStream.rangeClosed(1, 1_000_000)
.parallel()
.mapToDouble(n -> Math.sqrt(n) * Math.log(n + 1))
.sum();
System.out.println(sum);
}
}ปัจจัยที่ 3: ความสามารถในการแบ่ง
แหล่งข้อมูลที่แบ่งได้รวดเร็วและสม่ำเสมอจะเหมาะกับการทำงานแบบ parallel ได้แก่ อาร์เรย์ ArrayList และ IntStream.range ส่วน LinkedList และแหล่งข้อมูลที่ใช้ตัววนซ้ำจะแบ่งได้ไม่ดี
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) list.add(i);
long even = list.parallelStream().filter(n -> n % 2 == 0).count();
System.out.println(even);
}
}แหล่งข้อมูลที่ดี: อาร์เรย์และช่วง
ช่วงชนิดพื้นฐานมีขนาดที่ทราบแน่นอนและแบ่งได้ในเวลา O(1) จึงเป็นแหล่งข้อมูลแบบ parallel ที่เหมาะอย่างยิ่ง
import java.util.stream.LongStream;
public class Main {
public static void main(String[] args) {
long sum = LongStream.rangeClosed(1, 20_000_000)
.parallel()
.sum();
System.out.println(sum);
}
}แหล่งข้อมูลที่ไม่ดี: ตัวสร้างค่าแบบวนซ้ำ
Stream.iterate สร้างองค์ประกอบตามลำดับโดยนิยาม จึงไม่สามารถแบ่งได้จนกว่าองค์ประกอบจะถูกสร้างขึ้นจริง ทำให้เป็นแหล่งข้อมูลแบบ parallel ที่ไม่เหมาะนัก
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
long count = Stream.iterate(1, n -> n + 1)
.limit(1_000_000)
.parallel()
.filter(n -> n % 2 == 0)
.count();
System.out.println(count);
}
}ปัจจัยที่ 4: ขั้นตอนการรวมที่มีต้นทุนต่ำ
การทำงานแบบ parallel ต้องมีวิธีรวมผลลัพธ์บางส่วนที่ใช้ต้นทุนต่ำ sum และ count รวมกันได้ง่าย แต่การสร้างรายการที่เรียงลำดับหรือตัวรวบรวมที่ใช้โครงสร้างต้นไม้จำนวนมากจะมีต้นทุนการรวมสูง
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int max = IntStream.rangeClosed(1, 5_000_000)
.parallel()
.map(n -> n % 1000)
.max()
.getAsInt();
System.out.println(max);
}
}หลีกเลี่ยงกับงานที่รออินพุต/เอาต์พุต
สตรีมแบบ parallel มุ่งเป้าไปที่งานที่ใช้ CPU เป็นหลักบนพูลแบบ fork-join การดำเนินการอินพุต/เอาต์พุตแบบบล็อกจะทำให้พูลร่วมไม่มีเธรดว่าง และส่งผลเสียต่อทั้งแอปพลิเคชัน ให้ใช้ตัวจัดการเธรดเฉพาะสำหรับอินพุต/เอาต์พุตแทน
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long total = IntStream.rangeClosed(1, 1_000_000)
.parallel()
.mapToLong(n -> (long) n * n)
.sum();
System.out.println(total);
}
}วัดผล อย่าคาดเดา
วิธีเดียวที่เชื่อถือได้ในการทราบว่าการทำงานแบบ parallel ช่วยได้หรือไม่ คือ ทดสอบประสิทธิภาพด้วยข้อมูลที่ใกล้เคียงการใช้งานจริง การคาดเดาประสิทธิภาพจากความรู้สึกมักผิดพลาด
import java.util.stream.LongStream;
public class Main {
public static void main(String[] args) {
long start = System.nanoTime();
long sum = LongStream.rangeClosed(1, 50_000_000).parallel().sum();
long ms = (System.nanoTime() - start) / 1_000_000;
System.out.println("sum=" + sum + " took ~" + ms + "ms");
}
}รายการตรวจสอบที่ใช้ได้จริง
เลือกใช้การทำงานแบบ parallel เมื่อเป็นจริงทั้งหมด:
- N มีขนาดใหญ่ และ/หรืองานต่อองค์ประกอบใช้เวลามาก
- มีแหล่งข้อมูลที่แบ่งได้ เช่น อาร์เรย์, ArrayList หรือ range
- มีการรวมที่มีต้นทุนต่ำและมีสมบัติการจัดหมู่
- เป็นงานที่ใช้ CPU เป็นหลักและไม่มีอินพุต/เอาต์พุตแบบบล็อก
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
double avg = IntStream.rangeClosed(1, 10_000_000)
.parallel()
.mapToDouble(Math::sqrt)
.average()
.getAsDouble();
System.out.println(avg);
}
}ตรวจสอบความเข้าใจ
สถานการณ์ใดเหมาะสมที่สุดสำหรับสตรีมแบบ parallel?
สรุปทบทวน
คุณได้เรียนรู้ว่าเมื่อใดการทำงานแบบ parallel จึงช่วยได้:
- ประโยชน์เพิ่มขึ้นตาม N x Q (ขนาดข้อมูลคูณต้นทุนต่องค์ประกอบ)
- ต้องมีแหล่งข้อมูลที่แบ่งได้ เช่น อาร์เรย์, ArrayList หรือช่วง
- ต้องมีการรวมที่มีต้นทุนต่ำและมีสมบัติการจัดหมู่
- ควรเป็นงานที่ใช้ CPU เป็นหลัก หลีกเลี่ยงอินพุต/เอาต์พุตแบบบล็อก และวัดผลเสมอ
คำถามที่พบบ่อย
บทเรียน “เมื่อการประมวลผลแบบขนานช่วยได้” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เมื่อการประมวลผลแบบขนานช่วยได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เมื่อการประมวลผลแบบขนานช่วยได้”
ปัจจัยด้านปริมาณงานและขนาดข้อมูล คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “เมื่อการประมวลผลแบบขนานช่วยได้” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสร้างสตรีมแบบขนาน
- เมื่อการประมวลผลแบบขนานช่วยได้
- ความปลอดภัยของเธรดและผลข้างเคียง
- ข้อผิดพลาดที่พบบ่อย