บทที่ 6: Concurrency (การทำงานพร้อมกัน)
2 min readภาพรวม
นิยาม:
- Concurrency = เมื่อโค้ดตั้งแต่สองส่วนขึ้นไปทำงาน ราวกับว่า ทำงานพร้อมกัน (software mechanism)
- Parallelism = เมื่อมันทำงานพร้อมกัน จริง ๆ (hardware: multiple cores/CPUs)
Concurrency ไม่ใช่ทางเลือกอีกต่อไป: มันคือข้อบังคับสำหรับแอปพลิเคชันที่ต้องรับมือกับโลกจริงที่ทุกอย่างเป็น asynchronous
Topic 33: Breaking Temporal Coupling (ทำลาย coupling เชิงเวลา)
Tip 56: Analyze Workflow to Improve Concurrency: วิเคราะห์ workflow เพื่อเพิ่ม concurrency
Temporal coupling คือการ coupling ในเชิงเวลา: method A ต้องเรียกก่อน method B เสมอ, รัน report ได้ทีละอัน, ต้องรอหน้าจอ redraw ก่อนถึงรับ click ได้
ใช้ Activity Diagrams ระบุสิ่งที่ทำพร้อมกันได้และสิ่งที่ต้องทำตามลำดับ: แล้วหาโอกาสในการทำกิจกรรมที่ใช้เวลานาน (เช่น query database, เข้าถึง external service, รอ user input) ไปพร้อมกับงานอื่น
โอกาสสำหรับ Parallelism: แบ่งงานใหญ่ออกเป็นชิ้นอิสระ, ประมวลผลแต่ละชิ้นแบบ parallel, รวมผลลัพธ์
Topic 34: Shared State Is Incorrect State (shared state คือ state ที่ผิด)
Tip 57: Shared State Is Incorrect State
Tip 58: Random Failures Are Often Concurrency Issues
ปัญหา classic: server สองคนเห็น pie ชิ้นสุดท้ายในตู้, ทั้งคู่รับออเดอร์, ลูกค้าหนึ่งคนต้องผิดหวัง
ปัญหาไม่ได้อยู่ที่การเขียนข้อมูลแชร์กัน: แต่อยู่ที่การที่ไม่มีใครรับประกันได้ว่าภาพของ memory ที่ตัวเองเห็นนั้น consistent: การอ่านและอัปเดตค่าไม่ใช่ atomic operation
วิธีแก้ปัญหาแบบดั้งเดิม (และปัญหาของมัน):
- Semaphores/Mutexes: ทำงานได้ถ้า ทุกคน ทำตาม convention: ถ้าใครลืมใช้ semaphore ระบบก็พัง
- ทำให้ resource เป็น transactional: ย้าย logic การป้องกันไว้ที่ resource เอง: แต่ยังต้องจัดการ semaphore + exception handling อยู่ดี
- Multiple resource transactions: ซับซ้อนมากเมื่อต้องจัดการหลาย resource พร้อมกัน: ต้องคิดเผื่อการ "คืนของ" และ exception handling
"Doctor, it hurts when I do this.": "Then don't do that."
Topic 35: Actors and Processes (ตัวแสดงและกระบวนการ)
Tip 59: Use Actors For Concurrency Without Shared State
Actor คืออะไร: virtual processor ที่มี state ส่วนตัวและ mailbox เมื่อมีข้อความมาถึงและ actor ว่าง มันจะประมวลผลข้อความ: สร้าง actor ใหม่, ส่งข้อความไป actor อื่น, และสร้าง state ใหม่
คุณสมบัติสำคัญ:
- ไม่มีใครควบคุมจากส่วนกลาง
- state ทั้งหมดอยู่ใน messages และ local state ของแต่ละ actor: ไม่มี shared state
- ข้อความเป็น one-way: ไม่มี concept ของการ reply โดยตรง
- ประมวลผลทีละหนึ่งข้อความจนเสร็จ
ข้อดี: ไม่ต้องเขียนโค้ดจัดการ concurrency, ไม่มี shared state, ทำงานได้เหมือนกันบน single processor, multiple cores, หรือ networked machines
Erlang/Elixir เป็นตัวอย่างที่ดี: มี lightweight processes, supervision trees (จัดการ failure), และ hot-code loading
Topic 36: Blackboards (กระดานดำ)
Tip 60: Use Blackboards to Coordinate Workflow
ลองนึกถึงนักสืบที่ไขคดีฆาตกรรม หัวหน้าสารวัตรตั้งกระดานดำเขียนคำถาม นักสืบแต่ละคนเพิ่มข้อมูล, หลักฐาน, ข้อสันนิษฐาน ไม่มีใครต้องรู้ว่าใครอยู่ ทุกคนดู board และเพิ่มสิ่งที่ตัวเองรู้
คุณสมบัติของ blackboard:
- ผู้เข้าร่วม (detectives/agents/actors) ไม่จำเป็นต้องรู้จักกัน
- อาจมีความเชี่ยวชาญต่างกัน
- เข้า-ออกระบบได้ตลอดเวลา
- ไม่มีข้อจำกัดว่าต้องวางอะไรบน board
การประยุกต์ใช้กับซอฟต์แวร์: ระบบ mortgage/loan applications: กฎหมายซับซ้อน, ข้อมูลมาจากหลายแหล่งและมาถึงไม่พร้อมกัน, การมาถึงของข้อมูลใหม่อาจทำให้เกิดคำถามใหม่ blackboard + rules engine จัดการได้อย่างสง่างาม
Messaging systems สมัยใหม่ (Kafka, NATS): ทำหน้าที่คล้าย blackboard: มี persistence (event log) และ pattern matching ใช้เป็นทั้ง blackboard และ platform สำหรับ actors ได้