Showing posts with label go. Show all posts
Showing posts with label go. Show all posts

Wednesday, September 9, 2020

Golang: Mutexes and wait groups

 Mutexes and wait groups:

goroutines run in same address space so have shared memory access which need to be synchronized.


The variable greetings has data race condition.

Check using.

go run -race racedemo.go


//racedemo.go
// An example of a data race condition.
// Execute the program like so: "go run -race racedemo.go" to detect the race condition.
package main

import "fmt"

var greetings string
var howdyDone chan bool

func howdyGreetings() {

	greetings = "Howdy Gopher!"
	howdyDone <- true
}

func main() {

	howdyDone = make(chan bool, 1)
	go howdyGreetings()
	greetings = "Hello Gopher!"
	fmt.Println(greetings)
	<-howdyDone
}


go run -race mutex.go

// An example of solving the data race condition using a mutex.
package main

import (
	"fmt"
	"sync"
)

var greetings string
var howdyDone chan bool
var mutex = &sync.Mutex{}

func howdyGreetings() {

	mutex.Lock()
	greetings = "Howdy Gopher!"
	mutex.Unlock()
	howdyDone <- true
}

func main() {

	howdyDone = make(chan bool, 1)
	go howdyGreetings()
	mutex.Lock()
	greetings = "Hello Gopher!"
	fmt.Println(greetings)
	mutex.Unlock()
	<-howdyDone
}


waitgroup.


// An example of concurrently fetching web site URLs using a WaitGroup.
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"sync"
)

func fetchUrl(url string, wg *sync.WaitGroup) {

	// Decrement the WaitGroup counter once we've fetched the URL
	defer wg.Done()

	response, err := http.Get(url)
	if err != nil {
		log.Fatal("Failed to fetch the URL, ", url, " and encountered this error: ", err)
	} else {
		fmt.Println("Contents of url, ", url, ", is:\n")
		contents, err := ioutil.ReadAll(response.Body)

		response.Body.Close()
		if err != nil {
			log.Fatal("Failed to read the response body and encountered this error: ", err)
		}
		fmt.Println(string(contents), "\n")
	}

}

func main() {

	var wg sync.WaitGroup
	var urlList = []string{
		"http://www.golang.org/",
		"http://www.google.com/",
		"http://www.youtube.com/",
	}

	// Loop through the list of URLs
	for _, url := range urlList {
		// Increment the WaitGroup counter
		wg.Add(1)
		// Call the fetchURL function as a goroutine to fetch the URL
		go fetchUrl(url, &wg)
	}
	// Wait for the goroutines that are part of the WaitGroup to finish
	wg.Wait()

}


increment the waitgroup using Add method to tell how many goroutines to wait for.

defere wg.Done() --> defer/wait for surronding fn to return.

Golang: channels

 

package main
import "fmt"
func writeMessageToChannel(message chan string){
  message <- "Hello Uday!"
}
func main(){
  fmt.Println("Channel Demo")
  message := make(chan string)
  go writeMessageToChannel(message)//launches a separate goroutine to run parallelly
  fmt.Println("Greeting from the message channel: ",<-message)//will wait till channel sends the o/p
  close(message)//close channel
}

package main
import "fmt"
var done chan bool = make(chan bool)
func printGreetings(source string){
  for i:=0;i<9;i++{
   fmt.Println("Hello Uday!",i,source)
  }
  
  if source == "goroutine"{
    done <- true
  }
}
func main(){
  
  go printGreetings("goroutine")
  printGreetings("main function")
  
  <-done //this blocks the main function to wait till the done channel sends the o/p
}

Normal channels are synchronous, means both sending and receiving side will wait until the other side is ready.
Buffered channels are asynchronous, sending and receiving messages through the channel will not block unless the channel is full.
We can create a buffered channel using the built-in make function:
ch := make(chan type,capacity)
The difference from normal channel(capacity=1) syntax is we are passing the capacity with buffered channel.


package main
import "fmt"
var done chan bool = make(chan bool)

func main(){
 //we create a buffered channel of strings with a capacity of 3.
 //This means the channel buffer can hold up to 3 values
 messageQueue := make(chan string,3)
 messageQueue <- "one"
 messageQueue <- "two"
 messageQueue <- "three"
 //we drain the messageQueue by receiving all the values from the buffered channel
 fmt.Println(<-messageQueue)
 fmt.Println(<-messageQueue)
 fmt.Println(<-messageQueue)
}

Range over channels:
// An example of ranging over a channel.
//channelrange.go
package main

import "fmt"

func main() {

	// We create a buffered channel of strings with a capacity of 3
	// This means the channel buffer can hold up to 3 values
	messageQueue := make(chan string, 3)
	messageQueue <- "one"
	messageQueue <- "two"
	messageQueue <- "three"

	// Even though we close this non-empty channel, we can still receive
	// the remaining values (see below)
	close(messageQueue)

	// We use the range keyword to iterate over each element as it gets
	// received from the messageQueue.
	for m := range messageQueue {
		fmt.Println(m)
	}

}

// An example of sending and receiving a value through a channel.
//channeldemo.go
package main

import "fmt"

func writeMessageToChannel(message chan string) {

	message <- "Hello Gopher!"

}

func main() {

	fmt.Println("Channel Demo")

	message := make(chan string)
	go writeMessageToChannel(message)

	fmt.Println("Greeting from the message channel: ", <-message)

	close(message)
}

Tuesday, September 8, 2020

Golang: Declare a type

 Declare a type.


type typeName struct{

 field1 typeoffield1

 field2 typeoffield2

}


Creating an instance of  type with postion

t:=typeName{field1value,field2value}


Creating an instance of type with field names

t:=typeName{field2: field2value.field1:field1value}




can define methods using a pointer receiver(r *typeName).

The receiver is the implicit first argument to function.

a method is a function associated with a type.


type typeName struct{

 field1 typeoffield1

 field2 typeoffield2

}

func (r *typeName) methodName() returnType{


}

//calling t.methodName()



//triangle.go
package simpleshape

type Triangle struct {
	base   float64
	height float64
}

//serves as a constructor with reference to new Triangle instance.
//Not a method as pointer fn not there.
func NewTriangle(b float64, h float64) *Triangle {
	return &Triangle{base: b, height: h}
}

func (t *Triangle) Area() float64 {
	return (t.base * t.height) / 2
}

//rectangle.go
package simpleshape

type Rectangle struct {
	width  float64
	height float64
}

func NewRectangle(w float64, h float64) *Rectangle {
	return &Rectangle{width: w, height: h}

}

func (r *Rectangle) Area() float64 {
	return r.width * r.height
}



two have similar code in common, create inteface.

Declaring an interface

type InterfaceName interface{
  methodName1() returnType1
  methodName2() returnType2
}

A type implements an interface when it has defined all methods in the method list of an interface.
we can't provide field names, only methods in the interface.



//simpleshape.go
// Package simpleshape is a simple interface for representing geometric shapes.
package simpleshape

// The Shape type represents a geometric shape.
type Shape interface {
	Area() float64
}

// Calculates the area of a shape. The area calculation is based on the type of shape s.
func ShapeArea(s Shape) float64 {

	return s.Area()

}

//shapedemo.go
// A demonstration program using the simpleshape package.
package main

import (
	"fmt"

	"github.com/EngineerKamesh/gofullstack/volume1/section3/simpleshape"
)

func main() {

	r := simpleshape.NewRectangle(9, 6)
	t := simpleshape.NewTriangle(3, 6)

	fmt.Println("Area of myRectangle: ", simpleshape.ShapeArea(r))
	fmt.Println("Area of myTriangle: ", simpleshape.ShapeArea(t))

}

no subclasses concept in go.
We can use pieces of an implemenation by embedding types,either within a struct or interface.

type Reader interface{
 Read(p []byte)(n int,err error)
}

type Writer interface{
 Write(p []byte)(n int,err error)
}

type ReadWriter interface{
 Reader
 Writer
}

The Empty Interface
Every type in Go implements the empty interface.
interface{}

Some use cases:
--
-A function that returns a value of interface{} can return any type.
-We can store heterogeneous values in an array, slice, or map using the interface{} type.



//emptyinterfacedemo.go
// An example of an empty interface, and some useful things we can do with it.
package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/EngineerKamesh/gofullstack/volume1/section3/simpleshape"
)

func giveMeARandomShape() interface{} {

	var shape interface{}
	var randomShapesSlice []interface{} = make([]interface{}, 2)

	// Seed the random generator
	s := rand.NewSource(time.Now().UnixNano())
	r := rand.New(s)

	// Pick a random number, either 1 or 0
	randomNumber := r.Intn(2)
	fmt.Println("Random Number: ", randomNumber)

	// Let's make a new rectangle
	rectangle := simpleshape.NewRectangle(3, 6)

	// Let's make a new triangle
	triangle := simpleshape.NewTriangle(9, 18)

	// Let's store the shapes into a slice data structure
	randomShapesSlice[0] = rectangle
	randomShapesSlice[1] = triangle
	shape = randomShapesSlice[randomNumber]

	return shape
}

func main() {

	myRectangle := simpleshape.NewRectangle(4, 5)
	myTriangle := simpleshape.NewTriangle(2, 7)
	shapesSlice := []interface{}{myRectangle, myTriangle}
	for index, shape := range shapesSlice {
		fmt.Printf("Shape in index, %d, of the shapesSlice is a  %T\n", index, shape)
	}
	fmt.Println("\n")

	aRandomShape := giveMeARandomShape()
	fmt.Printf("The type of aRandomShape is %T\n", aRandomShape)
	switch t := aRandomShape.(type) {
	case *simpleshape.Rectangle:
		fmt.Println("I got back a rectangle with an area equal to ", t.Area())
	case *simpleshape.Triangle:
		fmt.Println("I got back a triangle with an area equal to ", t.Area())
	default:
		fmt.Println("I don't recognize what I got back!")
	}

}

Golang: Slice

 Slices are dynamic sized arrays.

So they are used frequently than arrays.

Arrays are value types and slices are referenced type.

So, changes made to them when we passed to function, they reflect outside also.




Declaring and initializing a slice.(we don't mention size there)
var sliceName []type=make([]type,length)

setting a value in the slice
sliceName[index]=value

Getting a value in the slice
sliceName[index]

len(mySlice)---current length
cap(mySize)--max length/capacity



// An example showing how to declare a slice and perform various operations using a slice.
package main

import "fmt"

// Slices get passed by reference into functions, meaning, if make changes to
// a slice within a function, our changes will be reflected to the slice that
// was passed into the function.

func populateIntegerSlice(input []int) {

	// We set values in a slice, just like we do with arrays using the square brackets
	// notation [] with the element index enclosed within the square brackets.
	input[0] = 3
	input[1] = 6
	input[2] = 9
	input[3] = 12
	input[4] = 15
}

func changingLineupExample() {

	// Declaring and initializing a slice representing the original band members of
	// rock band, INXS using a slice literal (notice it looks just like an array literal
	// except without the element count)
	fmt.Println("The original INXS lineup:")
	inxs := []string{"Michael", "Andrew", "Jon", "Tim", "Kirk", "Garry"}
	fmt.Println(inxs, "\n")

	// Michael left the band in 1997
	fmt.Println("The lineup without Michael:")
	inxs = append(inxs[:0], inxs[1:]...)
	fmt.Println(inxs, "\n")

	// JD joins the band in 2005
	fmt.Println("The lineup with a new member, JD:")
	inxs = append(inxs, "JD")
	fmt.Println(inxs, "\n")

}

func main() {

	// We use the make() built-in function to create a new slice of length 5.
	// Here we make a slice of integers of length 5.
	var mySlice []int = make([]int, 5)
	fmt.Printf("Contents of mySlice: %v\n\n", mySlice)

	populateIntegerSlice(mySlice)
	fmt.Printf("Contents of mySlice: %v\n", mySlice)
	// We can use the len() built-in function to return the length of the slice
	fmt.Println("The length of mySlice is: ", len(mySlice))
	// We can use the cap() built-in function to return the capacity of the slice
	fmt.Println("The capacity of mySlice is: ", cap(mySlice), "\n")

	// Add a new element to mySlice, and notice the changes to the length and
	// capacity of the slice
	fmt.Println("After adding a new element to mySlice...\n")
	mySlice = append(mySlice, 18)
	fmt.Printf("Contents of mySlice: %v\n", mySlice)
	fmt.Println("The length of mySlice is: ", len(mySlice))
	fmt.Println("The capacity of mySlice is: ", cap(mySlice), "\n")

	// This short hand notation allows us to get the elements from index 1 up to
	// (but not including) index 4.
	s := mySlice[1:4]
	fmt.Println("mySlice[1:4] ", s, "\n")

	// When you slice a slice, you get a reference back to that slice. Any changes you
	// make to the subslice will be reflected in the original slice.
	s[0] = 7 // this will cause mySlice[1] to be equal to 7
	fmt.Println("mySlice: ", mySlice)

	// All elements in myslice up to (not including) the element at index 4
	t := mySlice[:4]
	fmt.Println("mySlice[:4] ", t, "\n")

	// The elements from (and including) the element at index 1
	u := mySlice[1:]
	fmt.Println("mySlice[1:] ", u, "\n")

	changingLineupExample()
}

GoLang: Arrays

 Declaring an Array

var arrayName [length]type


setting a value in the array

arrayName[index]=value


getting a value in the array

arrayName[index]


Arrays are treated as values, not references.So when we pass array as argument to a function,a seperate local copy is created.



// Some examples of array declarations and showing how arrays are treated as values in Go.
package main

import "fmt"

// 1st attempt at populating the integer array
func populateIntegerArray(input [5]int) {

	input[0] = 3
	input[1] = 6
	input[2] = 9
	input[3] = 12
	input[4] = 15

}

// 2nd attempt at populating the integer array
func populateIntegerArrayWithReturnValue(input [5]int) [5]int {

	input[0] = 3
	input[1] = 6
	input[2] = 9
	input[3] = 12
	input[4] = 15
	return input
}

func beatlesArrayExample() {

	// Declare and initialize values in an array
	var beatles [4]string
	beatles[0] = "John"
	beatles[1] = "Paul"
	beatles[2] = "Ringo"
	beatles[3] = "George"
	fmt.Printf("Beatles consists of: %v\n", beatles)
	fmt.Println("The name of third band member in the beatles array is", beatles[2])

	fmt.Println("Length of beatles: ", len(beatles))

	// In Go, arrays are values. When we assign one array to another, all the elements from
	// the array on the right hand side are copied over to the array on the left hand side.
	var greatRockBandFromThe60s [4]string
	greatRockBandFromThe60s = beatles
	fmt.Printf("Members from a great rock band from the 1960s: %v\n", greatRockBandFromThe60s)

	// Since arrays are values, equality comparisons of two arrays are done value for value.
	// Note that the beatles array and the greatRockBandFromThe60s array have two different
	// addresses in memory. The value comparison only checks the values of the arrays, and
	// the memory address of the two arrays is not a criteria for the comparison.
	fmt.Printf("beatles mem address: %p\n", &beatles)
	fmt.Printf("greatRockBandFromThe60s mem address: %p\n", &greatRockBandFromThe60s)
	if beatles == greatRockBandFromThe60s {
		fmt.Println("The beatles array equals the greatRockBandFromThe60s array")
	}
}

func u2ArrayExample() {

	// Declare and initialize using the := operator. Instead of writing 4 lines of code
	// to initialize the array, we get the job done in 1 line of code using an array
	// literal value
	u2 := [4]string{"Bono", "Edge", "Adam", "Larry"}
	fmt.Printf("U2 consists of: %v\n", u2)
	fmt.Println("The name of second band member in the u2 array is", u2[1])

	fmt.Println("Length of u2: ", len(u2))
}

func main() {

	// Declare an array of 5 integers
	// Note: If we do not initialize a value for the array, they will default to the
	// zero value of the type. In the case of integers, we expect the zero value to be 0.
	var myArray [5]int
	fmt.Printf("Contents of myArray: %v\n\n", myArray)

	// Arrays are passed by value to functions, meaning a copy of the array is passed
	// and not a reference (pointer) to the array.
	populateIntegerArray(myArray)
	fmt.Printf("Contents of myArray: %v\n\n", myArray)

	myArray = populateIntegerArrayWithReturnValue(myArray)
	fmt.Printf("Contents of myArray: %v\n\n", myArray)

	// Use the built in len function to get the length of an array
	fmt.Println("Length of myArray: ", len(myArray))

	beatlesArrayExample()

	u2ArrayExample()

}

Matrix:Multidimensional arrays 




// An example of a multidimensional array, a 3x4 matrix.
package main

import (
	"fmt"
)

func main() {

	// Here we create a multi-dimensional array, a 3x4 matrix (3 rows, 4 columns)
	myMatrix := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}

	// Let's print a value from a cell in each row of the matrix
	fmt.Println("Value at [0][0]: ", myMatrix[0][0])
	fmt.Println("Value at [1][1]: ", myMatrix[1][1])
	fmt.Println("Value at [2][2]: ", myMatrix[2][2])
	fmt.Println("\n")

	// First attempt at printing the matrix
	fmt.Printf("%+v\n", myMatrix)
	fmt.Println("\n")

	// A better looking matrix output to the screen
	printThreeByFourMatrix(myMatrix)
}

// A function to print the 3x4 matrix in a more pretty manner
func printThreeByFourMatrix(inputMatrix [3][4]int) {

	rowLength := len(inputMatrix)
	columnLength := len(inputMatrix[0])

	for i := 0; i < rowLength; i++ {
		for j := 0; j < columnLength; j++ {
			fmt.Printf("%5d ", inputMatrix[i][j])
		}
		fmt.Println()
	}

}

Arrays are fixed sized. Slices are dynamic arrays.

Go install fails with error: no install location for directory xxx outside GOPATH

 C:\Users\UdayKiranReddy\go\src>go install

go install: no install location for directory C:\Users\UdayKiranReddy\go\src outside GOPATH

        For more details see: 'go help gopath'


If you see above error.


Then set this variable before running "go install"


set GOBIN=%GOPATH%\bin

Then, go install works and the compiled exe will be saved to the GOBIN folder.

Reference

Golang: Packages


import alias:
package main

import f "fmt"

func main(){

 f.Println("adsasds")

}

greetings.go
package greetingspackage
import "fmt"
func PrintGreetings(){
 fmt.Println("I'm printing a message from printgreetings")
}
func printGreetingsUnexported(){
 fmt.Println("I'm printing a message from printgreetings unexported")
}

Note: captial first letter functioname can be exported.
GopherGreetings.go
package greetingspackage
import "fmt"
var MagicNumber int
func GopherGreetings(){
fmt.Println("Gopher greetings function")
printGreetingsUnexported()//As same package
}

//executed first
func init(){
MagicNumber = 108
}

useGreetings.go
package main
import(
 "fmt"
 "github.com/EngineerKamesh/gofullstack/volume1/section2/greetingspackage"
)
func main(){
 greetingspackage.PrintGreetings()
 greetingspackage.GopherGreetings()
 fmt.Println("The value of Magic Number is:",greetingpackage.MagicNumber)
}

go install
usegreetings