쉽고 빠른 Go 시작하기(5)

이지수·2022년 10월 21일
0

Backend Loadmap

목록 보기
11/22
post-thumbnail

URLChecker

정상적으로 작동하는 URL인지 체크해주는 미니 프로젝트 입니다.

hitURL

main.go

package main

import (
	"errors"
	"fmt"
	"net/http"
)

var errRequestFailed = errors.New("Request failed")

func main() {
	urls := []string{
		"https://www.airbnb.com/",
		"https://www.google.com/",
		"https://www.amazon.com/",
		"https://www.reddit.com/",
		"https://www.google.com/",
	}
	for _, url := range urls {
		hitURL(url)
	}
}

func hitURL(url string) error {
	fmt.Println("Checking:", url)
	resp, err := http.Get(url)
	if err != nil || resp.StatusCode >= 400 { // url이 없거나 StatusCode가 400 이상이라면
		return errRequestFailed
	}
	return nil
}

// Checking: https://www.airbnb.com/
// Checking: https://www.google.com/
// Checking: https://www.amazon.com/
// Checking: https://www.reddit.com/
// Checking: https://www.google.com/

Status Code

  • 1xx(정보) : 요청을 받았으며 프로세스를 계속 진행
  • 2xx(성공) : 요청을 성공적으로 받았으며 인식, 수용
  • 3xx(리다이렉션) : 요청 완료를 위해 추가 작업 조치 필요
  • 4xx(클라이언트 오류) : 요청의 문법이 잘못되었거나 요청을 처리할 수 없음
  • 5xx(서버 오류) : 서버가 명백히 유효한 요청에 대한 충족 실패

위의 urlChecker는 url을 하나씩 순차적으로 체크하기 때문에 느립니다.

Goroutines

Goroutines은 다른 함수와 동시에 실행시키는 함수 입니다.
Goroutines을 사용하려면 함수 앞에 go를 붙여주기만하면 됩니다.

func main() {
	go sexyCount("jisoo")
    	sexycount("lee")
}

func sexyCount(person string) {
	for i:=0;i<2;i++ {
    	fmt.Println(person, "is sexy", i)
        time.Sleep(time.Second) // time은 go 패키지
    }
}

// lee is sexy 0
// jisoo is sexy 0
// jisoo is sexy 1
// lee is sexy 1
// lee is sexy 2
// jisoo is sexy 2

함수 앞에 go를 붙이면 jisoo is sexy와 lee is sexy를 동시에 출력됩니다. sexyCount 두 함수가 동시에 실행되는 것입니다.
출력 결과를 보면 두 함수가 동시에 출력됩니다.

주의

func main() {
	go sexyCount("jisoo")
    	go sexycount("lee")
}

하지만 두 함수 모두에 go 를 붙히게되면 main 함수가 바로 종료되기 때문에 두 함수 모두 실행되지 않습니다.
Gorountines는 main 함수가 실행되고 있을 경우에만 유효합니다.

Channels

channel은 goroutine과 goroutine, 혹은 메인함수 사이에 정보를 전달하기 위한 방법입니다.

func main() {
	// Channels
	c := make(chan string) // channel 생성
	people := [2]string{"jisoo", "lee"}
	for _, person := range people {
		go isSexy(person, c)
	}
	for i := 0; i < len(people); i++ {
		fmt.Println(<-c) // channel로부터 메세지를 가져옴
	}
}

func isSexy(person string, c chan string) {
	time.Sleep(time.Second * 10)
	c <- person + " is sexy" // channel로 메세지를 보냄
}

// jisoo is sexy
// lee is sexy

rule

  1. main 함수가 끝나면 goroutines는 무의미합니다.
  2. 어떤 타입의 데이터를 보내고 받을 것인지 구체적으로 지정해줘야 합니다.
  3. channel로 메세지를 전달 방식은 c <- 메세지 입니다.

Fast URLChecker

type requestResult struct {
	url    string
	status string
}

var errRequestFailed = errors.New("Request failed")

func main() {
	results := make(map[string]string)
	c := make(chan requestResult)
	urls := []string{
		"https://www.airbnb.com/",
		"https://www.google.com/",
		"https://www.amazon.com/",
		"https://www.reddit.com/",
		"https://www.google.com/",
		"https://soundcloud.com/",
		"https://www.facebook.com/",
		"https://www.instagram.com/",
		"https://academy.nomadcoders.co/",
	}
	for _, url := range urls {
		go hitURL(url, c)
	}

	for i := 0; i < len(urls); i++ {
		result := <-c
		results[result.url] = result.status
	}

	for url, status := range results {
		fmt.Println(url, status)
	}

}

func hitURL(url string, c chan<- requestResult) { // chan<- : SEND only
	resp, err := http.Get(url)
	status := "OK"
	if err != nil || resp.StatusCode >= 400 {
		status = "FAILED"
	}
	c <- requestResult{url: url, status: status}
}

// https://www.amazon.com/ OK
// https://www.reddit.com/ FAILED
// https://www.instagram.com/ OK
// https://www.google.com/ OK
// https://www.airbnb.com/ OK
// https://soundcloud.com/ OK
// https://www.facebook.com/ OK
// https://academy.nomadcoders.co/ OK

출력 시간은 가장 오래 걸리는 하나의 url을 체크하는 시간과 같습니다.
처음의 hitURL처럼 하나의 url체크를 마치고 다음으로 넘어가는 것이아니라 url을 동시에 체크하기 때문에 출력 속도가 매우 빠릅니다.

참고
쉽고 빠른 Go 시작하기

0개의 댓글