Go ด้วยกัน Go ได้ไกล-pointers, struct, goroutines, channel, mutex [EP.5]
Pointers
= Refer memory address by&
and use value by*
Struct
= Like class in Python (but nothing method and OOP feature).Goroutine
= Lightweight thread.Channel
= Ways to return mutivalues with different types.Mutex
= To prevent goroutines to edit the same data in the same time.
1. Pointers (การอ้างอิง address ด้วย & และเอา value ออกมาด้วย *)
ในการทำ
API
จะใช้เยอะ เพราะจะได้performance
ที่ดีแบบที่ไม่ต้องจองvalue
เหมือนtype
แบบอื่นๆ เพราะจองแค่address
ในmemory
เท่านั้น
- เป็นการระบุว่าสิ่งที่เราจะหาอยู่ที่ไหน (แต่ไม่ได้ครอบครอง)
- ค่าในตัวแปร pointers เป็นเพียง address ในหน่วยความจำ
- ช่วยให้เราเปลี่ยนแปลงค่าที่ต้นทาง โดยไม่ต้องเปลี่ยนแปลงตำแหน่ง memory (เพราะปกติเวลาเราเปลี่ยนค่าใน value จะเป็นการเปลี่ยนค่าใน memory หรือมีการเขียนใหม่ใน RAM อ่ะนะ มันจึงช้ากว่า…เพราะไม่ได้ใช้ตำแหน่งเดิมไง)
- Pointer ใน Go มีไว้แค่อ้างอิงตำแหน่งเท่านั้นนะ ไม่สามารถคำนวณ math ได้
- เราจะใช้
*
ในการแทน pointer นะ โดยค่าเริ่มต้นคือnil
นะ เช่นvar p *int
p เป็น pointer ที่มี type แบบ int - เราจะใช้
&
เพื่อสร้าง pointer ที่ชี้ไปที่ค่าตัวแปรนั้นๆ เช่น
i := 42 // ตัวแปร i เก็บเลข42 ไว้
p = &i // ถัดมาตัวแปร p เก็บ address ของ i ไว้
- เราจะใช้
*
ดึงค่าภายใต้address
ที่pointer
นั้นชี้อยู่ออกมา
fmt.Println(*p) // อ่านค่า pointer p โดยเป็นตำแหน่งที่ i อยู่นะ
*p = 21 // เป็นการ set ค่า 21 เข้าไปที่ pointer p หรือ ที่อยู่ของตัวแปร i นั่นเอง (ไม่งงเนอะ)... พูดง่ายๆ เอาเลข 21 ไปใส่ในตัวแปร i นั่นเอง
จำง่ายๆนะ
- ใช้
&
ในการชี้ไปหา
เช่น&i
คือpoint to i
- ใช้
*
ไปเอา value ออกมา
เช่น*p
คือ เอาvalue
ที่เก็บไว้ในตำแหน่งของp
ออกมา หรือ
ถ้าจะใส่ค่าใหม่ก็*p = <new value>
ได้เลย
2. Struct (โครงสร้างข้อมูล)
เป็น data type แบบหนึ่ง ที่ใช้ในการรวมกลุ่มของตัวแปรหลายๆตัวที่มีหลายๆ types เข้าด้วยกัน และเก็บค่าเข้าไปได้ด้วย
- ง่ายๆคือ การรวมฟิลด์เข้ามาไว้ด้วยกัน
- จิงๆ ผมว่าคล้ายๆกับ class ใน Python เลยนะ
(แต่เป็น class ที่มีเพียง attribute, และไม่มี method ภายใน + inherit ไม่ได้) - เพราะไม่มี method ภายใน การจะให้มันทำอะไรต่อได้ ก็สร้าง function มารับ struct นั้นไปทำต่อได้เลย (ตามภาพด้านล่างเลยนะ อธิบายอย่างละเอียด)
3. Goroutines
ในการเขียนโปรแกรมจะมี Sync
and Async
ซึ่งการทำงานแบบ Async ใน Go เราสามารถะใช้ Goroutines
ได้เลยซึ่งเป็น lightweight thread
(ถูกจัดการโดย runtime in Go + ใช้ resource น้อยกว่าการสร้าง thread จริงๆ)
- ในการใช้งาน เราจะใช้
keyword
go
ไปนำหน้าfunction
นั้นๆไว้นั่นเอง พูดง่ายๆ วางgo
ไว้ข้างหน้าจะทำให้function
นั้นเป็นasync
(เหมือนไปทำงานใน background นั่นเอง หรือconcurrently
) - ลองดูตัวอย่างคับ
4. Channel
เป็น another key feature in go เพื่อให้ goroutines สามารถสื่อสารกันได้อย่างปลอดภัย โดยเป็นการเชื่อม type เข้าด้วยกัน
โดยสามารถส่งและรับค่าผ่าน <-
- Channel จะเหมือนกับ map, slice ตรงที่ต้องสร้างขึ้นมาก่อนถึงจะนำไปใช่ได้ ดูตัวอย่างเลยดีกว่าคับ
5. Mutex
มาจาก Mutual Exclusion
เป็นกลไกที่ใช้ป้องกันไม่ให้หลาย Goroutines
เข้าถึงและแก้ไขข้อมูลเดียวกัน ในเวลาเดียวกัน ซึ่งอาจทำให้เกิดข้อผิดพลาดในการประมวลผล (race condition)
พูดง่ายๆ มันทำให้ synchronus
นั่นเอง
- ในการใช้งาน เราสามารถใช้
sync.Mutex
จาก libsync
เพื่อจัดการการเข้าถึงข้อมูลที่ใช้ร่วมกันได้อย่างปลอดภัย (ป้องกันการเข้าถึงข้อมูลก้อนเดียวกัน ในเวลาเดียวกัน) sync.Mutex
มี 2 methods คือLock
,Unlock
ให้เราใช้ได้
package main
import (
"fmt"
"sync"
)
var (
counter int
mutex sync.Mutex
)
func increment(wg *sync.WaitGroup) {
mutex.Lock() // ล็อก mutex เพื่อป้องกันการเข้าถึงทรัพยากรที่ใช้ร่วมกัน
counter++ // ส่วนที่สำคัญ: เพิ่มค่า counter
mutex.Unlock() // ปลดล็อก mutex
wg.Done()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait() // รอให้ goroutines ทั้งหมดทำงานเสร็จ
fmt.Println("ค่าสุดท้ายของ counter:", counter)
}
If you think it’s useful for you, just clap your hands 👏 to be encouraged me.
แล้วพบกันใหม่ตอนถัดไปคับ