sync.Mutex & sync.RWMutex
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 63 dari 107.
Meskipun channel adalah cara yang diutamakan di Go untuk mengoordinasikan goroutine, terkadang kamu perlu melindungi data bersama secara langsung. Package sync menyediakan mutex: pengunci yang memastikan hanya satu goroutine yang mengakses sumber daya pada satu waktu.
Sebuah sync.Mutex memiliki dua method: Lock() dan Unlock(). Saat sebuah goroutine memanggil Lock(), goroutine itu mendapat akses eksklusif. Goroutine lain yang memanggil Lock() akan terblokir hingga Unlock() dipanggil:
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
c.value++
c.mu.Unlock()
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}Menggunakan defer c.mu.Unlock() memastikan kunci dilepas meskipun fungsi mengembalikan nilai lebih awal atau mengalami panic: pola yang umum dan direkomendasikan.
Saat pembacaan sering dilakukan tetapi penulisan jarang, sync.RWMutex menawarkan kinerja yang lebih baik. Ini memungkinkan beberapa pembaca mengakses secara bersamaan, tetapi penulis mendapat akses eksklusif:
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func (c *Cache) Get(key string) string {
c.mu.RLock() // beberapa pembaca dapat mengakses secara bersamaan
defer c.mu.RUnlock()
return c.data[key]
}
func (c *Cache) Set(key, value string) {
c.mu.Lock() // akses eksklusif untuk menulis
defer c.mu.Unlock()
c.data[key] = value
}Gunakan RLock()/RUnlock() untuk operasi baca dan Lock()/Unlock() untuk operasi tulis. Ini memungkinkan pembacaan dilakukan secara bersamaan sekaligus memastikan penulisan aman.
Tantangan
MudahMari kita membangun sistem inventaris aman untuk konkurensi yang melacak tingkat stok produk. Sistemmu akan menangani pembacaan dan penulisan secara bersamaan dengan aman menggunakan mutex, sehingga integritas data tetap terjaga saat beberapa operasi berlangsung secara bersamaan.
Kamu akan mengatur kodemu dalam dua file:
inventory.go: Definisikan sistem manajemen inventaris aman untuk konkurensi.Buat struct
Inventoryyang menyimpan jumlah produk dalam map dan menggunakansync.RWMutexuntuk melindungi akses. Inventarismu harus mendukung operasi berikut:NewInventory() *Inventory: Membuat inventaris baru dengan map yang sudah diinisialisasiAddStock(product string, quantity int): Menambahkan jumlah ke stok produk. Gunakan kunci eksklusif karena operasi ini mengubah dataGetStock(product string) int: Mengembalikan stok produk saat ini, atau 0 jika tidak ditemukan. Gunakan kunci baca karena operasi ini hanya membaca dataRemoveStock(product string, quantity int) bool: Mengurangi jumlah dari stok jika stok mencukupi. Mengembalikantruejika berhasil,falsejika stok tidak mencukupi. Gunakan kunci eksklusif
Ingatlah untuk menggunakan
defersaat membuka kunci agar kunci selalu dilepas dengan benar.main.go: Baca operasi dan tunjukkan cara kerja inventaris aman untuk konkurensi.Baca jumlah operasi, lalu proses setiap operasi. Setiap operasi memiliki tipe (
add,get, atauremove), nama produk, dan, untuk operasiadd/remove, jumlahnya.Untuk setiap operasi, cetak hasilnya:
add: CetakAdded [quantity] [product]get: Cetak[product]: [stock] in stockremove: CetakRemoved [quantity] [product]jika berhasil, atauInsufficient stock for [product]jika tidak
Input berikut akan diberikan:
- Baris 1: Jumlah operasi (bilangan bulat)
- Baris-baris berikutnya: Untuk setiap operasi:
- Tipe operasi (
add,get, atauremove) - Nama produk
- Jumlah (hanya untuk operasi
adddanremove)
- Tipe operasi (
Contohnya, jika diberikan:
5
add
apples
50
get
apples
remove
apples
30
remove
apples
25
get
applesOutputmu seharusnya:
Added 50 apples
apples: 50 in stock
Removed 30 apples
Insufficient stock for apples
apples: 20 in stockRWMutex memungkinkan beberapa pemanggilan GetStock membaca secara bersamaan, sedangkan AddStock dan RemoveStock mendapatkan akses eksklusif saat mengubah inventaris.
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Baca jumlah operasi
line, _ := reader.ReadString('\n')
numOps, _ := strconv.Atoi(strings.TrimSpace(line))
// Buat inventaris baru
inventory := NewInventory()
// Proses setiap operasi
for i := 0; i < numOps; i++ {
// Baca jenis operasi
opLine, _ := reader.ReadString('\n')
opType := strings.TrimSpace(opLine)
// Baca nama produk
productLine, _ := reader.ReadString('\n')
product := strings.TrimSpace(productLine)
// TODO: Tangani setiap jenis operasi (add, get, remove)
// Untuk "add" dan "remove", baca jumlah dari input
// Panggil method inventaris yang sesuai
// Cetak hasil sesuai deskripsi tantangan
switch opType {
case "add":
// TODO: Baca jumlah, tambahkan stok, cetak hasil
case "get":
// TODO: Ambil stok, cetak hasil
case "remove":
// TODO: Baca jumlah, kurangi stok, cetak hasil yang sesuai
}
}
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online