മലയാളം

ഗോയുടെ കൺകറൻസി ഫീച്ചറുകളെക്കുറിച്ചുള്ള ഒരു സമ്പൂർണ്ണ ഗൈഡ്. കാര്യക്ഷമവും സ്കെയിലബിളുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനായി ഗോറൂട്ടിനുകളും ചാനലുകളും പ്രായോഗിക ഉദാഹരണങ്ങളോടെ ഇതിൽ വിശദീകരിക്കുന്നു.

ഗോ കൺകറൻസി: ഗോറൂട്ടിനുകളുടെയും ചാനലുകളുടെയും ശക്തി പ്രയോജനപ്പെടുത്തൽ

ഗോ, പലപ്പോഴും ഗോലാങ് എന്ന് അറിയപ്പെടുന്നു, അതിൻ്റെ ലാളിത്യം, കാര്യക്ഷമത, കൺകറൻസിക്കുള്ള ഇൻ-ബിൽറ്റ് പിന്തുണ എന്നിവയ്ക്ക് പേരുകേട്ടതാണ്. ഒരേസമയം ഒന്നിലധികം ജോലികൾ നിർവഹിക്കാൻ പ്രോഗ്രാമുകളെ കൺകറൻസി അനുവദിക്കുന്നു, ഇത് പെർഫോമൻസും പ്രതികരണശേഷിയും മെച്ചപ്പെടുത്തുന്നു. ഗോ ഇത് രണ്ട് പ്രധാന ഫീച്ചറുകളിലൂടെയാണ് നേടുന്നത്: ഗോറൂട്ടിനുകൾ, ചാനലുകൾ എന്നിവ. ഈ ബ്ലോഗ് പോസ്റ്റ് എല്ലാ തലങ്ങളിലുമുള്ള ഡെവലപ്പർമാർക്ക് പ്രായോഗിക ഉദാഹരണങ്ങളും ഉൾക്കാഴ്ചകളും നൽകിക്കൊണ്ട് ഈ ഫീച്ചറുകളെക്കുറിച്ച് വിശദമായി പ്രതിപാദിക്കുന്നു.

എന്താണ് കൺകറൻസി?

ഒരു പ്രോഗ്രാമിന് ഒരേസമയം ഒന്നിലധികം ജോലികൾ നിർവഹിക്കാനുള്ള കഴിവിനെയാണ് കൺകറൻസി എന്ന് പറയുന്നത്. കൺകറൻസിയെ പാരലലിസത്തിൽ നിന്ന് വേർതിരിച്ചറിയേണ്ടത് പ്രധാനമാണ്. കൺകറൻസി ഒരേ സമയം ഒന്നിലധികം ജോലികൾ *കൈകാര്യം* ചെയ്യുന്നതിനെക്കുറിച്ചാണ്, അതേസമയം പാരലലിസം ഒരേ സമയം ഒന്നിലധികം ജോലികൾ *ചെയ്യുന്നതിനെക്കുറിച്ചാണ്*. ഒരു സിംഗിൾ പ്രോസസ്സറിന് ജോലികൾക്കിടയിൽ അതിവേഗം മാറിക്കൊണ്ട് കൺകറൻസി കൈവരിക്കാൻ കഴിയും, ഇത് ഒരേസമയം നിർവ്വഹിക്കുന്നതിൻ്റെ പ്രതീതി സൃഷ്ടിക്കുന്നു. എന്നാൽ പാരലലിസത്തിന്, ജോലികൾ ഒരേസമയം നിർവഹിക്കാൻ ഒന്നിലധികം പ്രോസസ്സറുകൾ ആവശ്യമാണ്.

ഒരു റെസ്റ്റോറൻ്റിലെ ഒരു ഷെഫിനെ സങ്കൽപ്പിക്കുക. പച്ചക്കറികൾ അരിയുക, സോസുകൾ ഇളക്കുക, മാംസം ഗ്രിൽ ചെയ്യുക തുടങ്ങിയ ജോലികൾക്കിടയിൽ മാറിക്കൊണ്ട് ഷെഫ് ഒന്നിലധികം ഓർഡറുകൾ കൈകാര്യം ചെയ്യുന്നതുപോലെയാണ് കൺകറൻസി. ഒരേ സമയം ഒന്നിലധികം ഷെഫുകൾ ഓരോരുത്തരും ഓരോ ഓർഡറിൽ പ്രവർത്തിക്കുന്നതുപോലെയാണ് പാരലലിസം.

ഗോയുടെ കൺകറൻസി മോഡൽ, സിംഗിൾ പ്രോസസ്സറിലാണോ മൾട്ടിപ്പിൾ പ്രോസസ്സറുകളിലാണോ പ്രവർത്തിക്കുന്നത് എന്നത് പരിഗണിക്കാതെ, കൺകറൻ്റ് പ്രോഗ്രാമുകൾ എഴുതുന്നത് എളുപ്പമാക്കുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നു. സ്കേലബിളും കാര്യക്ഷമവുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള ഒരു പ്രധാന നേട്ടമാണ് ഈ ഫ്ലെക്സിബിലിറ്റി.

ഗോറൂട്ടിനുകൾ: ഭാരം കുറഞ്ഞ ത്രെഡുകൾ

ഒരു ഗോറൂട്ടിൻ എന്നത് ഭാരം കുറഞ്ഞതും സ്വതന്ത്രമായി പ്രവർത്തിക്കുന്നതുമായ ഒരു ഫംഗ്ഷനാണ്. ഇതിനെ ഒരു ത്രെഡായി കരുതാം, പക്ഷേ വളരെ കാര്യക്ഷമമാണ്. ഒരു ഗോറൂട്ടിൻ ഉണ്ടാക്കുന്നത് വളരെ ലളിതമാണ്: ഒരു ഫംഗ്ഷൻ കോളിന് മുമ്പായി `go` എന്ന കീവേഡ് ചേർത്താൽ മതി.

ഗോറൂട്ടിനുകൾ നിർമ്മിക്കുന്നു

ഇവിടെ ഒരു അടിസ്ഥാന ഉദാഹരണം നൽകുന്നു:

package main

import (
	"fmt"
	"time"
)

func sayHello(name string) {
	for i := 0; i < 5; i++ {
		fmt.Printf("Hello, %s! (Iteration %d)\n", name, i)
		time.Sleep(100 * time.Millisecond)
	}
}

func main() {
	go sayHello("Alice")
	go sayHello("Bob")

	// Wait for a short time to allow goroutines to execute
	time.Sleep(500 * time.Millisecond)
	fmt.Println("Main function exiting")
}

ഈ ഉദാഹരണത്തിൽ, `sayHello` ഫംഗ്ഷൻ രണ്ട് വ്യത്യസ്ത ഗോറൂട്ടിനുകളായി പ്രവർത്തിക്കുന്നു, ഒന്ന് "Alice" നും മറ്റൊന്ന് "Bob" നും വേണ്ടി. പ്രധാന ഫംഗ്ഷൻ എക്സിറ്റ് ആകുന്നതിന് മുമ്പ് ഗോറൂട്ടിനുകൾക്ക് പ്രവർത്തിക്കാൻ സമയം ലഭിക്കുന്നുണ്ടെന്ന് ഉറപ്പാക്കാൻ `main` ഫംഗ്ഷനിലെ `time.Sleep` പ്രധാനമാണ്. അതില്ലെങ്കിൽ, ഗോറൂട്ടിനുകൾ പൂർത്തിയാകുന്നതിന് മുമ്പുതന്നെ പ്രോഗ്രാം അവസാനിച്ചേക്കാം.

ഗോറൂട്ടിനുകളുടെ പ്രയോജനങ്ങൾ

ചാനലുകൾ: ഗോറൂട്ടിനുകൾക്കിടയിലുള്ള ആശയവിനിമയം

ഗോറൂട്ടിനുകൾ കോഡ് കൺകറൻ്റായി എക്സിക്യൂട്ട് ചെയ്യാൻ ഒരു മാർഗ്ഗം നൽകുമ്പോൾ, അവയ്ക്ക് പരസ്പരം ആശയവിനിമയം നടത്തുകയും സിൻക്രൊണൈസ് ചെയ്യുകയും ചെയ്യേണ്ടിവരും. ഇവിടെയാണ് ചാനലുകൾ വരുന്നത്. ഗോറൂട്ടിനുകൾക്കിടയിൽ നിങ്ങൾക്ക് ഡാറ്റ അയയ്ക്കാനും സ്വീകരിക്കാനും കഴിയുന്ന ഒരു ടൈപ്പ്ഡ് ചാലകമാണ് ചാനൽ.

ചാനലുകൾ നിർമ്മിക്കുന്നു

`make` ഫംഗ്ഷൻ ഉപയോഗിച്ചാണ് ചാനലുകൾ നിർമ്മിക്കുന്നത്:

ch := make(chan int) // Creates a channel that can transmit integers

നിങ്ങൾക്ക് ബഫർഡ് ചാനലുകളും നിർമ്മിക്കാം, അവ ഒരു റിസീവർ തയ്യാറാകാതെ തന്നെ ഒരു നിശ്ചിത എണ്ണം മൂല്യങ്ങൾ സൂക്ഷിക്കാൻ കഴിയും:

ch := make(chan int, 10) // Creates a buffered channel with a capacity of 10

ഡാറ്റ അയക്കുകയും സ്വീകരിക്കുകയും ചെയ്യുക

`<-` ഓപ്പറേറ്റർ ഉപയോഗിച്ചാണ് ഒരു ചാനലിലേക്ക് ഡാറ്റ അയക്കുന്നത്:

ch <- 42 // Sends the value 42 to the channel ch

`<-` ഓപ്പറേറ്റർ ഉപയോഗിച്ച് തന്നെയാണ് ഒരു ചാനലിൽ നിന്ന് ഡാറ്റ സ്വീകരിക്കുന്നതും:

value := <-ch // Receives a value from the channel ch and assigns it to the variable value

ഉദാഹരണം: ഗോറൂട്ടിനുകളെ ഏകോപിപ്പിക്കാൻ ചാനലുകൾ ഉപയോഗിക്കുന്നു

ഗോറൂട്ടിനുകളെ ഏകോപിപ്പിക്കാൻ ചാനലുകൾ എങ്ങനെ ഉപയോഗിക്കാമെന്ന് കാണിക്കുന്ന ഒരു ഉദാഹരണം ഇതാ:

package main

import (
	"fmt"
	"time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Printf("Worker %d started job %d\n", id, j)
		time.Sleep(time.Second)
		fmt.Printf("Worker %d finished job %d\n", id, j)
		results <- j * 2
	}
}

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)

	// Start 3 worker goroutines
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results)
	}

	// Send 5 jobs to the jobs channel
	for j := 1; j <= 5; j++ {
		jobs <- j
	}
	close(jobs)

	// Collect the results from the results channel
	for a := 1; a <= 5; a++ {
		fmt.Println("Result:", <-results)
	}
}

ഈ ഉദാഹരണത്തിൽ:

ഒന്നിലധികം ഗോറൂട്ടിനുകൾക്കിടയിൽ ജോലി വിതരണം ചെയ്യാനും ഫലങ്ങൾ ശേഖരിക്കാനും ചാനലുകൾ എങ്ങനെ ഉപയോഗിക്കാമെന്ന് ഈ ഉദാഹരണം കാണിക്കുന്നു. `jobs` ചാനൽ ക്ലോസ് ചെയ്യുന്നത്, കൂടുതൽ ജോലികളൊന്നും പ്രോസസ്സ് ചെയ്യാനില്ലെന്ന് വർക്കർ ഗോറൂട്ടിനുകളെ അറിയിക്കുന്നതിന് നിർണായകമാണ്. ചാനൽ ക്ലോസ് ചെയ്തില്ലെങ്കിൽ, വർക്കർ ഗോറൂട്ടിനുകൾ കൂടുതൽ ജോലികൾക്കായി അനിശ്ചിതമായി കാത്തിരിക്കും.

സെലക്ട് സ്റ്റേറ്റ്മെൻ്റ്: ഒന്നിലധികം ചാനലുകളിൽ മൾട്ടിപ്ലക്സിംഗ്

`select` സ്റ്റേറ്റ്മെൻ്റ് ഒരേസമയം ഒന്നിലധികം ചാനൽ പ്രവർത്തനങ്ങൾക്കായി കാത്തിരിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു. കേസുകളിലൊന്ന് മുന്നോട്ട് പോകാൻ തയ്യാറാകുന്നതുവരെ ഇത് ബ്ലോക്ക് ചെയ്യുന്നു. ഒന്നിലധികം കേസുകൾ തയ്യാറാണെങ്കിൽ, ഒരെണ്ണം ക്രമരഹിതമായി തിരഞ്ഞെടുക്കപ്പെടുന്നു.

ഉദാഹരണം: ഒന്നിലധികം ചാനലുകൾ കൈകാര്യം ചെയ്യാൻ സെലക്ട് ഉപയോഗിക്കുന്നു

package main

import (
	"fmt"
	"time"
)

func main() {
	c1 := make(chan string, 1)
	c2 := make(chan string, 1)

	go func() {
		time.Sleep(2 * time.Second)
		c1 <- "Message from channel 1"
	}()

	go func() {
		time.Sleep(1 * time.Second)
		c2 <- "Message from channel 2"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("Received:", msg1)
		case msg2 := <-c2:
			fmt.Println("Received:", msg2)
		case <-time.After(3 * time.Second):
			fmt.Println("Timeout")
			return
		}
	}
}

ഈ ഉദാഹരണത്തിൽ:

ഒന്നിലധികം കൺകറൻ്റ് പ്രവർത്തനങ്ങൾ കൈകാര്യം ചെയ്യുന്നതിനും ഒരു ചാനലിൽ അനിശ്ചിതമായി ബ്ലോക്ക് ചെയ്യുന്നത് ഒഴിവാക്കുന്നതിനും `select` സ്റ്റേറ്റ്മെൻ്റ് ഒരു ശക്തമായ ഉപകരണമാണ്. ടൈംഔട്ടുകൾ നടപ്പിലാക്കുന്നതിനും ഡെഡ്‌ലോക്കുകൾ തടയുന്നതിനും `time.After` ഫംഗ്ഷൻ പ്രത്യേകിച്ചും ഉപയോഗപ്രദമാണ്.

ഗോയിലെ സാധാരണ കൺകറൻസി പാറ്റേണുകൾ

ഗോയുടെ കൺകറൻസി ഫീച്ചറുകൾ നിരവധി സാധാരണ പാറ്റേണുകൾക്ക് അനുയോജ്യമാണ്. ഈ പാറ്റേണുകൾ മനസ്സിലാക്കുന്നത് കൂടുതൽ കരുത്തുറ്റതും കാര്യക്ഷമവുമായ കൺകറൻ്റ് കോഡ് എഴുതാൻ നിങ്ങളെ സഹായിക്കും.

വർക്കർ പൂളുകൾ

മുമ്പത്തെ ഉദാഹരണത്തിൽ കാണിച്ചതുപോലെ, വർക്കർ പൂളുകളിൽ ഒരു കൂട്ടം വർക്കർ ഗോറൂട്ടിനുകൾ ഉൾപ്പെടുന്നു, അവ ഒരു പങ്കിട്ട ക്യൂവിൽ (ചാനൽ) നിന്ന് ടാസ്ക്കുകൾ പ്രോസസ്സ് ചെയ്യുന്നു. ഒന്നിലധികം പ്രോസസ്സറുകൾക്കിടയിൽ ജോലി വിഭജിക്കുന്നതിനും ത്രൂപുട്ട് മെച്ചപ്പെടുത്തുന്നതിനും ഈ പാറ്റേൺ ഉപയോഗപ്രദമാണ്. ഉദാഹരണങ്ങളിൽ ഉൾപ്പെടുന്നവ:

ഫാൻ-ഔട്ട്, ഫാൻ-ഇൻ

ഒന്നിലധികം ഗോറൂട്ടിനുകളിലേക്ക് ജോലി വിതരണം ചെയ്യുകയും (ഫാൻ-ഔട്ട്) തുടർന്ന് ഫലങ്ങൾ ഒരൊറ്റ ചാനലിലേക്ക് സംയോജിപ്പിക്കുകയും (ഫാൻ-ഇൻ) ചെയ്യുന്നതാണ് ഈ പാറ്റേൺ. ഡാറ്റയുടെ സമാന്തര പ്രോസസ്സിംഗിനായി ഇത് പലപ്പോഴും ഉപയോഗിക്കുന്നു.

ഫാൻ-ഔട്ട്: ഡാറ്റ ഒരേസമയം പ്രോസസ്സ് ചെയ്യുന്നതിനായി ഒന്നിലധികം ഗോറൂട്ടിനുകൾ പ്രവർത്തിപ്പിക്കുന്നു. ഓരോ ഗോറൂട്ടിനും പ്രോസസ്സ് ചെയ്യാനുള്ള ഡാറ്റയുടെ ഒരു ഭാഗം ലഭിക്കുന്നു.

ഫാൻ-ഇൻ: ഒരു ഗോറൂട്ടിൻ എല്ലാ വർക്കർ ഗോറൂട്ടിനുകളിൽ നിന്നുമുള്ള ഫലങ്ങൾ ശേഖരിക്കുകയും അവയെ ഒരൊറ്റ ഫലത്തിലേക്ക് സംയോജിപ്പിക്കുകയും ചെയ്യുന്നു. ഇതിന് പലപ്പോഴും വർക്കർമാരിൽ നിന്ന് ഫലങ്ങൾ സ്വീകരിക്കുന്നതിന് ഒരു ചാനൽ ഉപയോഗിക്കേണ്ടിവരും.

ഉദാഹരണ സാഹചര്യങ്ങൾ:

പൈപ്പ്ലൈനുകൾ

ഒരു പൈപ്പ്ലൈൻ എന്നത് ഘട്ടങ്ങളുടെ ഒരു ശ്രേണിയാണ്, ഇവിടെ ഓരോ ഘട്ടവും മുൻ ഘട്ടത്തിൽ നിന്നുള്ള ഡാറ്റ പ്രോസസ്സ് ചെയ്യുകയും ഫലം അടുത്ത ഘട്ടത്തിലേക്ക് അയയ്ക്കുകയും ചെയ്യുന്നു. സങ്കീർണ്ണമായ ഡാറ്റ പ്രോസസ്സിംഗ് വർക്ക്ഫ്ലോകൾ സൃഷ്ടിക്കുന്നതിന് ഇത് ഉപയോഗപ്രദമാണ്. ഓരോ ഘട്ടവും സാധാരണയായി അതിൻ്റേതായ ഗോറൂട്ടിനിൽ പ്രവർത്തിക്കുകയും ചാനലുകൾ വഴി മറ്റ് ഘട്ടങ്ങളുമായി ആശയവിനിമയം നടത്തുകയും ചെയ്യുന്നു.

ഉപയോഗത്തിനുള്ള ഉദാഹരണങ്ങൾ:

കൺകറൻ്റ് ഗോ പ്രോഗ്രാമുകളിലെ എറർ ഹാൻഡ്‌ലിംഗ്

കൺകറൻ്റ് പ്രോഗ്രാമുകളിൽ എറർ ഹാൻഡ്‌ലിംഗ് നിർണായകമാണ്. ഒരു ഗോറൂട്ടിന് ഒരു പിശക് നേരിടുമ്പോൾ, അത് ഭംഗിയായി കൈകാര്യം ചെയ്യുകയും മുഴുവൻ പ്രോഗ്രാമിനെയും തകരാറിലാക്കുന്നത് തടയുകയും ചെയ്യേണ്ടത് പ്രധാനമാണ്. ചില മികച്ച രീതികൾ ഇതാ:

ഉദാഹരണം: ചാനലുകൾ ഉപയോഗിച്ചുള്ള എറർ ഹാൻഡ്‌ലിംഗ്

package main

import (
	"fmt"
	"time"
)

func worker(id int, jobs <-chan int, results chan<- int, errs chan<- error) {
	for j := range jobs {
		fmt.Printf("Worker %d started job %d\n", id, j)
		time.Sleep(time.Second)
		fmt.Printf("Worker %d finished job %d\n", id, j)
		if j%2 == 0 { // Simulate an error for even numbers
			errs <- fmt.Errorf("Worker %d: Job %d failed", id, j)
			results <- 0 // Send a placeholder result
		} else {
			results <- j * 2
		}
	}
}

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)
	errs := make(chan error, 100)

	// Start 3 worker goroutines
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results, errs)
	}

	// Send 5 jobs to the jobs channel
	for j := 1; j <= 5; j++ {
		jobs <- j
	}
	close(jobs)

	// Collect the results and errors
	for a := 1; a <= 5; a++ {
		select {
		case res := <-results:
			fmt.Println("Result:", res)
		case err := <-errs:
			fmt.Println("Error:", err)
		}
	}
}

ഈ ഉദാഹരണത്തിൽ, വർക്കർ ഗോറൂട്ടിനുകളിൽ നിന്ന് പ്രധാന ഫംഗ്ഷനിലേക്ക് പിശക് സന്ദേശങ്ങൾ അയയ്‌ക്കാൻ ഞങ്ങൾ ഒരു `errs` ചാനൽ ചേർത്തു. വർക്കർ ഗോറൂട്ടിൻ ഇരട്ട സംഖ്യകളുള്ള ജോലികൾക്ക് ഒരു പിശക് അനുകരിക്കുന്നു, `errs` ചാനലിൽ ഒരു പിശക് സന്ദേശം അയക്കുന്നു. പ്രധാന ഫംഗ്ഷൻ ഓരോ വർക്കർ ഗോറൂട്ടിനിൽ നിന്നും ഒരു ഫലമോ പിശകോ സ്വീകരിക്കാൻ ഒരു `select` സ്റ്റേറ്റ്മെൻ്റ് ഉപയോഗിക്കുന്നു.

സിൻക്രൊണൈസേഷൻ പ്രിമിറ്റീവുകൾ: മ്യൂട്ടെക്സുകളും വെയ്റ്റ്ഗ്രൂപ്പുകളും

ഗോറൂട്ടിനുകൾക്കിടയിൽ ആശയവിനിമയം നടത്താനുള്ള ഏറ്റവും നല്ല മാർഗം ചാനലുകളാണെങ്കിലും, ചിലപ്പോൾ പങ്കിട്ട ഉറവിടങ്ങളിൽ നിങ്ങൾക്ക് കൂടുതൽ നേരിട്ടുള്ള നിയന്ത്രണം ആവശ്യമായി വരും. ഇതിനായി ഗോ മ്യൂട്ടെക്സുകൾ, വെയ്റ്റ്ഗ്രൂപ്പുകൾ തുടങ്ങിയ സിൻക്രൊണൈസേഷൻ പ്രിമിറ്റീവുകൾ നൽകുന്നു.

മ്യൂട്ടെക്സുകൾ

ഒരു മ്യൂട്ടെക്സ് (മ്യൂച്വൽ എക്സ്ക്ലൂഷൻ ലോക്ക്) പങ്കിട്ട ഉറവിടങ്ങളെ കൺകറൻ്റ് ആക്‌സസ്സിൽ നിന്ന് സംരക്ഷിക്കുന്നു. ഒരേ സമയം ഒരു ഗോറൂട്ടിന് മാത്രമേ ലോക്ക് പിടിക്കാൻ കഴിയൂ. ഇത് ഡാറ്റാ റേസുകൾ തടയുകയും ഡാറ്റയുടെ സ്ഥിരത ഉറപ്പാക്കുകയും ചെയ്യുന്നു.

package main

import (
	"fmt"
	"sync"
)

var ( // shared resource
	counter int
	m sync.Mutex
)

func increment() {
	m.Lock() // Acquire the lock
	counter++
	fmt.Println("Counter incremented to:", counter)
	m.Unlock() // Release the lock
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			increment()
		}()
	}

	wg.Wait() // Wait for all goroutines to finish
	fmt.Println("Final counter value:", counter)
}

ഈ ഉദാഹരണത്തിൽ, `increment` ഫംഗ്ഷൻ `counter` വേരിയബിളിനെ കൺകറൻ്റ് ആക്‌സസ്സിൽ നിന്ന് സംരക്ഷിക്കാൻ ഒരു മ്യൂട്ടെക്സ് ഉപയോഗിക്കുന്നു. കൗണ്ടർ വർദ്ധിപ്പിക്കുന്നതിന് മുമ്പ് `m.Lock()` മെത്തേഡ് ലോക്ക് നേടുന്നു, കൗണ്ടർ വർദ്ധിപ്പിച്ച ശേഷം `m.Unlock()` മെത്തേഡ് ലോക്ക് റിലീസ് ചെയ്യുന്നു. ഇത് ഒരേ സമയം ഒരു ഗോറൂട്ടിന് മാത്രമേ കൗണ്ടർ വർദ്ധിപ്പിക്കാൻ കഴിയൂ എന്ന് ഉറപ്പാക്കുന്നു, ഡാറ്റാ റേസുകൾ തടയുന്നു.

വെയ്റ്റ്ഗ്രൂപ്പുകൾ

ഒരു കൂട്ടം ഗോറൂട്ടിനുകൾ പൂർത്തിയാകുന്നതുവരെ കാത്തിരിക്കാനാണ് വെയ്റ്റ്ഗ്രൂപ്പ് ഉപയോഗിക്കുന്നത്. ഇത് മൂന്ന് രീതികൾ നൽകുന്നു:

മുമ്പത്തെ ഉദാഹരണത്തിൽ, `sync.WaitGroup` ഉറപ്പാക്കുന്നത്, അന്തിമ കൗണ്ടർ മൂല്യം പ്രിൻ്റ് ചെയ്യുന്നതിന് മുമ്പ് പ്രധാന ഫംഗ്ഷൻ 100 ഗോറൂട്ടിനുകളും പൂർത്തിയാകുന്നതുവരെ കാത്തിരിക്കുന്നു എന്നാണ്. `wg.Add(1)` ഓരോ ഗോറൂട്ടിനും കൗണ്ടർ വർദ്ധിപ്പിക്കുന്നു. ഒരു ഗോറൂട്ടിൻ പൂർത്തിയാകുമ്പോൾ `defer wg.Done()` കൗണ്ടർ കുറയ്ക്കുന്നു, `wg.Wait()` എല്ലാ ഗോറൂട്ടിനുകളും പൂർത്തിയാകുന്നതുവരെ (കൗണ്ടർ പൂജ്യത്തിൽ എത്തുന്നതുവരെ) ബ്ലോക്ക് ചെയ്യുന്നു.

കോൺടെക്സ്റ്റ്: ഗോറൂട്ടിനുകളും റദ്ദാക്കലും കൈകാര്യം ചെയ്യൽ

`context` പാക്കേജ് ഗോറൂട്ടിനുകളെ നിയന്ത്രിക്കാനും റദ്ദാക്കൽ സിഗ്നലുകൾ പ്രചരിപ്പിക്കാനും ഒരു മാർഗം നൽകുന്നു. ദീർഘനേരം പ്രവർത്തിക്കുന്ന പ്രവർത്തനങ്ങൾക്കോ ബാഹ്യ സംഭവങ്ങളെ അടിസ്ഥാനമാക്കി റദ്ദാക്കേണ്ട പ്രവർത്തനങ്ങൾക്കോ ഇത് പ്രത്യേകിച്ചും ഉപയോഗപ്രദമാണ്.

ഉദാഹരണം: റദ്ദാക്കുന്നതിനായി കോൺടെക്സ്റ്റ് ഉപയോഗിക്കുന്നു

package main

import (
	"context"
	"fmt"
	"time"
)

func worker(ctx context.Context, id int) {
	for {
		select {
		case <-ctx.Done():
			fmt.Printf("Worker %d: Canceled\n", id)
			return
		default:
			fmt.Printf("Worker %d: Working...\n", id)
			time.Sleep(time.Second)
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	// Start 3 worker goroutines
	for w := 1; w <= 3; w++ {
		go worker(ctx, w)
	}

	// Cancel the context after 5 seconds
	time.Sleep(5 * time.Second)
	fmt.Println("Canceling context...")
	cancel()

	// Wait for a while to allow workers to exit
	time.Sleep(2 * time.Second)
	fmt.Println("Main function exiting")
}

ഈ ഉദാഹരണത്തിൽ:

കോൺടെക്സ്റ്റുകൾ ഉപയോഗിക്കുന്നത്, ആവശ്യമില്ലാത്തപ്പോൾ ഗോറൂട്ടിനുകളെ ഭംഗിയായി ഷട്ട് ഡൗൺ ചെയ്യാനും, റിസോഴ്സ് ലീക്കുകൾ തടയാനും, നിങ്ങളുടെ പ്രോഗ്രാമുകളുടെ വിശ്വാസ്യത മെച്ചപ്പെടുത്താനും അനുവദിക്കുന്നു.

ഗോ കൺകറൻസിയുടെ യഥാർത്ഥ ലോക പ്രയോഗങ്ങൾ

ഗോയുടെ കൺകറൻസി ഫീച്ചറുകൾ വൈവിധ്യമാർന്ന യഥാർത്ഥ ലോക പ്രയോഗങ്ങളിൽ ഉപയോഗിക്കുന്നു, അവയിൽ ഉൾപ്പെടുന്നവ:

ഗോ കൺകറൻസിക്കുള്ള മികച്ച രീതികൾ

കൺകറൻ്റ് ഗോ പ്രോഗ്രാമുകൾ എഴുതുമ്പോൾ മനസ്സിൽ സൂക്ഷിക്കേണ്ട ചില മികച്ച രീതികൾ ഇതാ:

ഉപസംഹാരം

ഗോയുടെ കൺകറൻസി ഫീച്ചറുകൾ, പ്രത്യേകിച്ച് ഗോറൂട്ടിനുകളും ചാനലുകളും, കൺകറൻ്റും പാരലലുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിന് ശക്തവും കാര്യക്ഷമവുമായ ഒരു മാർഗം നൽകുന്നു. ഈ ഫീച്ചറുകൾ മനസ്സിലാക്കുകയും മികച്ച രീതികൾ പിന്തുടരുകയും ചെയ്യുന്നതിലൂടെ, നിങ്ങൾക്ക് കരുത്തുറ്റതും സ്കേലബിളും ഉയർന്ന പ്രകടനവുമുള്ള പ്രോഗ്രാമുകൾ എഴുതാൻ കഴിയും. ഈ ടൂളുകൾ ഫലപ്രദമായി പ്രയോജനപ്പെടുത്താനുള്ള കഴിവ് ആധുനിക സോഫ്റ്റ്‌വെയർ ഡെവലപ്‌മെൻ്റിന്, പ്രത്യേകിച്ച് വിതരണ സംവിധാനങ്ങളിലും ക്ലൗഡ് കമ്പ്യൂട്ടിംഗ് പരിതസ്ഥിതികളിലും ഒരു നിർണായക വൈദഗ്ധ്യമാണ്. ഗോയുടെ രൂപകൽപ്പന, മനസ്സിലാക്കാൻ എളുപ്പമുള്ളതും പ്രവർത്തിപ്പിക്കാൻ കാര്യക്ഷമവുമായ കൺകറൻ്റ് കോഡ് എഴുതുന്നതിനെ പ്രോത്സാഹിപ്പിക്കുന്നു.