[Packt] Go lang Study

2021. 2. 14. 05:52카테고리 없음

728x90

너무 귀여운 Go lang 쨩 .... 배워보고 싶었다.

1. Introduction

Go lang은 2007년 9월에 Robert Grimmer, Rob Pike, Ken Thompson이 분산운영체제와 관련된 작업을 하면서 시작 됨

동시성, 분산처리와 연관 있음 !!

 

GO 특징

  • 인터프리터와 컴파일 기능을 둘 다 가짐
  • 고루틴
    • 멀티쓰레드 메커니즘이지만 자체적인 스케줄러에 의해 관리되는 경량 쓰레드이며, OS 에서 관리하는 경량 쓰레드보다 더 경량입니다.
    • 일급객체로 정수와 실수와 같은 데이터 타입과 동급으로 취급
  • 컨벤션이 통일되어 있음.
    • VS Code에서 저장을 누르는 순간 formatter가 포맷을 맞춰 줌.
  • Simple is best 라는 철학
    • go test 로 unit test 할 수 있음
    • Test 로 시작하고 *testing.T 를 매개변수로 사용하면 테스트 함수인 것으로 간주
    • go test -cover 옵션을 이용하면 테스트 커버리지 레포팅도 할 수 있다.
  • go doc 으로 문서화를 지원함 !

 

Go 사용처

  • 쿠버네티스, 도커에서 사용 함
  • YouTube 개발에 사용하는 언어

 


[설치]

1. http://golang.org/dl에서 Go 를 다운 받는다.

2. vscode extension에서 go 를 추가한다.

3. main.go 를 작성해본다

package main

import (
	"fmt"
)

var (
	test string = "test"
)

const (
   cont = "con"
)

func main(){
	fmt.Println("hello world")
    fmt.Println(test)
}
$ go run hello-world.go
hello world
프로그램을 실행할 때 !
$ go build hello-world.go
Binary로 만들고 싶을 때 ! Build

2. 변수

var a,b string = "init", "init"
a := "init"
  • Go는 명시적으로 선언됨
  • := 문법을 사용하여 단축표현 할 수 있음
  • fmt.Printf("%#v", 변수) 로 #을 붙이면 변수의 type 또한 출력된다


3. 반복문

for i:=1 ; i <9 ; i++{
 fmt.Println(i)
}

4. 조건문

if i == 0 {
 fmt.Println(i)
}
else {

}
switch i {
	case 1 :
 		fmt.Println(i)
    case 2:
    
}

5. Pointer

package main

import (
	"fmt"
)

var (
	test string = "test"
    ptest *string = &test
)

func main(){
    fmt.Println(ptest)  // address 가 찍혀나옴
    fmt.Println(*ptest)  // 값이 찍혀나옴
}

6. 배열

b := []int{1, 2, 3, 4, 5}
fmt.Println("dcl:", b)
// dcl: [1 2 3 4 5]

fmt.Println(b[0])
// 1

 

a := make([]string,3)
// 길이가 3인 빈 배열 만들기
// 내장함수 make

a = append(a,"d")
// 문자열 추가하기

copy(b,a)
// a를 복사하기
Python의 slicing 도 비슷하게 구현이 된다

7. 맵

  config := map[string]string{
  "debug":  "1",
  "logLevel": "warn",
  "version": "1.2.1",
  }
for key, value := range config {
블라브라
}
delete(맵이름,키이름)

8. 자료형


9. Typedef

type id string
var id1 id
type user struct {
  name  string 
  age   int 
  balance float64 
  member bool 
} 

user.name = "블라블라"

10. 함수

func plusPlus(a, b, c int) int {
	return a + b + c
}

// 파이썬 처럼 다중 반환이 된다


// func foo(nums ...int)    이렇게 다중 가변 인자도 된다

11. 익명함수

람다, 익명함수, arrow function, closure .. 뭐 다 비슷한 느낌으로 본다

package main

import (
	"fmt"
)

func main() {
	add5 := adder(3)

	fmt.Println(add5()) //4
	fmt.Println(add5()) //5
	fmt.Println(add5()) //6
}

func adder(a int) func() int {
	b := 0

	return func() int {
		b++
		return a + b
	}
}
  • adder(3) == adder(a int)    <- 자유변수
  • b는 묶인 변수 (bound) <- Closes over

12. 인터페이스

type rect struct {
    width, height float64
}
type circle struct {
	radius float64
}


func (r rect) area() float64 {
	return r.width * r.height
}
func (c circle) area() float64 {
	return math.Pi * c.radius * c.radius
}



func main() {
	r := rect{width: 3, height: 4}
	c := circle{radius: 5}
	measure(r)
	measure(c)
}


func measure(g geometry) {
	fmt.Println(g)
	fmt.Println(g.area())
	fmt.Println(g.perim())
}

13. Init 함수

func init() {
  fmt.Println("Hello, ",name)
}
  • 제일 먼저 실행된다


14. Go routine

땀땀땀땀.... 드디어 GO 언어의 핵심인 분산처리에 도달했습니다.

박수 ..!! 🙌🙌🙌

func hello() {
  fmt.Println("hello world")
}


func main() {
  fmt.Println("Start")
  go hello() // 얘가 고 루틴 입니다
  fmt.Println("End")
  • 근데 이렇게 하면 hello() 함수가 호출이 안 될거에요
  • 왜냐면, the main() function will not care about the hello() function as these functions will run independently

Note: The important thing to remember is that Go is not a parallel language, but concurrent, which means that Goroutines do not work in an independent manner, but each Goroutine is split into smaller parts and each Goroutine runs one of its subparts at a time.

  • hello 가 시작하고 죽던 상관 없이 main이 먼저 끝나버린 거거든요.
  • 그러면 어떻게 해야할까요?
package main
 
import (
	"fmt"
	"sync"
)

var (
	wg = &sync.WaitGroup{}
)


func hello() {
  fmt.Println("hello world")
  "wg.Done()"
}


func main() {

  "wg.Add(1)" //asynchronous operation that adds 1 to the group 

  fmt.Println("Start")
  go hello() // 얘가 고 루틴 입니다
  fmt.Println("End")
  
  "wg.Wait()"
}
  • 요렇게 중간중간에 wg를 끼워 넣어서 sync를 맞추어 주어야 합니다. 참 쉽죠 ?
  • 이번에는 얘가 정말 분산으로 되는지 한번 볼게요
package main

import (
	"fmt"
	"sync"
)

var (
	wg = &sync.WaitGroup{}
)

func main() {

	fmt.Println("Start")

	iter()

	wg.Wait()           // 너 작업 끝날 때 까지 기다려줄게 !

	fmt.Println("End")

}

func iter() {
	for i := 0; i < 10; i++ {

		wg.Add(1) // go routine이 시작하기 전에 async 할 queue 를 추가 시켜줘요
                  // 작업 끝날 때 까지 맘대로 죽지마 !

		go func(i int) {

			fmt.Println(i)
			wg.Done()  // 나 작업 끝났어 !
		}(i)
	}
}


/** 결과
Start
0
1
9
2
6
4
5
7
8
3
End
*/

 

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

var (
	wg  = &sync.WaitGroup{}
	sum = int32(0)
)

func main() {

	fmt.Println("Start")

	wg.Add(2)
	go iter(1, 49)
	go iter(50, 100)

	wg.Wait()

	fmt.Println("End")
	fmt.Println(sum)

}

func iter(from, to int) {
	for i := from; i <= to; i++ {
		atomic.AddInt32(&sum, int32(i))
	}
	wg.Done()
}
  • 또 요로코롬 atomic 한 연산도 지원합니다.

15. 채널

Channels는 동시에 실행되고 있는 고루틴을 연결해주는 파이프입니다. 한 고루틴으로부터 채널에 값을 전달하면 다른 고루틴에서 이 값을 받을 수 있습니다.

package main

import (
	"fmt"
	"sync"
)

func main() {

	messages := make(chan string) // 채널을 생성합니다
	messages <- "string ting"
	msg := <-messages
    
	fmt.Println(msg)

}
  • 만약에 이렇게 쓰면 잘 안돌아 갈겁니다. 단 하나의 루틴으로 메시지를 보낸 후 실행을 차단하고 수신할 수 있는 다른 루틴이 없기 때문에 교착상태가 발생합니다.
package main

import (
	"fmt"
	"sync"
)

func main() {

	messages := make(chan string)
	// 채널을 생성합니다

	// messages <- "string ting"
	go func() { messages <- "ping" }()
	// 채널을 send 합니다.

	msg := <-messages
	fmt.Println(msg)

}

/** 결과
ping
*/
  • 고 루틴을 만들어 주면 됩니다 ..! 짠 !
package main

import (
	"fmt"
)

func main() {

	messages := make(chan string, 2)
	// 2개 채널을 생성합니다

	messages <- "ping"
	messages <- "pong"

	fmt.Println(<-messages)
	fmt.Println(<-messages)

}

/** 결과
ping
pong
*/

■ References

 

[Golang] Go Routine (고 루틴) - Golang의 꽃 [기본]

Golang에는 Go Routine(이하 "고루틴")으로 불리는 동시성 예약어가 있다. 즉, main 함수를 돌리면서 순차적이 아니라 익명함수나 함수를 동시에 실행시킬 수 있다는 뜻이다. 바로 아래 예제를 살펴보

underflow101.tistory.com

 

Go by Example

 

mingrammer.com