반응형
    
    
    
  SMALL
    미래(Future)
미래 디자인 패턴은 결국 동일한 고루틴 또는 다른 고루틴에 의해 실행될 알고리즘을 작성할 수 있게 해줍니다.
package future
type SuccessFunc func(string)
type FailFunc func(error)
type ExecuteStringFunc func() (string, error)
type MaybeString struct {
	successFunc SuccessFunc
	failFunc    FailFunc
}
func (s *MaybeString) Success(f SuccessFunc) *MaybeString {
	s.successFunc = f
	return s
}
func (s *MaybeString) Fail(f FailFunc) *MaybeString {
	s.failFunc = f
	return s
}
func (s *MaybeString) Execute(f ExecuteStringFunc) {
	go func(s *MaybeString) {
		str, err := f()
		if err != nil {
			s.failFunc(err)
		} else {
			s.successFunc(str)
		}
	}(s)
}Test Code
package future
import (
	"errors"
	"fmt"
	"sync"
	"testing"
	"time"
)
func TestStringOrError_Execute(t *testing.T) {
	future := &MaybeString{}
	t.Run("Success result", func(t *testing.T) {
		var wg sync.WaitGroup
		wg.Add(1)
		//Timeout!
		go timeout(t, &wg)
		future.Success(func(s string) {
			t.Log(s)
			wg.Done()
		}).Fail(func(e error) {
			t.Fail()
			wg.Done()
		})
		future.Execute(func() (string, error) {
			return "Hello World!", nil
		})
		wg.Wait()
	})
	t.Run("Error result", func(t *testing.T) {
		var wg sync.WaitGroup
		wg.Add(1)
		future.Success(func(s string) {
			t.Fail()
			wg.Done()
		}).Fail(func(e error) {
			t.Log(e.Error())
			wg.Done()
		})
		future.Execute(func() (string, error) {
			return "", errors.New("Error ocurred")
		})
		wg.Wait()
	})
	t.Run("Closure Success result", func(t *testing.T) {
		var wg sync.WaitGroup
		wg.Add(1)
		//Timeout!
		go timeout(t, &wg)
		future.Success(func(s string) {
			t.Log(s)
			wg.Done()
		}).Fail(func(e error) {
			t.Fail()
			wg.Done()
		})
		future.Execute(setContext("Hello"))
		wg.Wait()
	})
}
func setContext(msg string) ExecuteStringFunc {
	msg = fmt.Sprintf("%s Closure!\n", msg)
	return func() (string, error) {
		return msg, nil
	}
}
func timeout(t *testing.T, wg *sync.WaitGroup) {
	time.Sleep(time.Second)
	t.Log("Timeout!")
	t.Fail()
	wg.Done()
}파이프라인(Pipeline)
파이프라인 디자인 패턴은 어떤 논리에 따라 서로 연결된 고루틴의 복잡한 동기 흐름을 구축하는 강력한 패턴입니다.
package pipeline
func LaunchPipeline(amount int) int {
	return <-sum(power(generator(amount)))
}
func generator(max int) <-chan int {
	outChInt := make(chan int, 100)
	go func() {
		for i := 1; i <= max; i++ {
			outChInt <- i
		}
		close(outChInt)
	}()
	return outChInt
}
func power(in <-chan int) <-chan int {
	out := make(chan int, 100)
	go func() {
		for v := range in {
			out <- v * v
		}
		close(out)
	}()
	return out
}
func sum(in <-chan int) <-chan int {
	out := make(chan int, 100)
	go func() {
		var sum int
		for v := range in {
			sum += v
		}
		out <- sum
		close(out)
	}()
	return out
}Test Code
package pipeline
import "testing"
func TestLaunchPipeline(t *testing.T) {
	tableTest := [][]int{
		{3, 14},
		{5, 55}}
	var res int
	for _, test := range tableTest {
		res = LaunchPipeline(test[0])
		if res != test[1] {
			t.Fatal()
		}
		t.Logf("%d == %d\n", res, test[1])
	}
}워커 풀(Worker Pool)
동시성에 대한 이전의 접근 방식 중 일부와 관련하여 우리가 직면할 수 있는 문제 중 하나는 무한한 컨텍스트입니다. 우리는 앱이 무제한의 고루틴을 만들게 할 수 없습니다.고루틴은 가볍지만, 고루틴이 하는 일은 매우 무거울 수 있으므로 앱이 무제한의 고루틴을 만들게 할 수 없고, 워커 풀 디자인 패턴은 이 문제를 해결하는 데 도움이 됩니다.
package main
import "time"
type Dispatcher interface {
	LaunchWorker(w WorkerLauncher)
	MakeRequest(Request)
	Stop()
}
type dispatcher struct {
	inCh chan Request
}
func (d *dispatcher) LaunchWorker(w WorkerLauncher) {
	w.LaunchWorker(d.inCh)
}
func (d *dispatcher) Stop() {
	close(d.inCh)
}
func (d *dispatcher) MakeRequest(r Request) {
	select {
	case d.inCh <- r:
	case <-time.After(time.Second * 5):
		return
	}
}
func NewDispatcher(b int) Dispatcher {
	return &dispatcher{
		inCh: make(chan Request, b),
	}
}package main
import (
	"fmt"
	"strings"
)
type WorkerLauncher interface {
	LaunchWorker(in chan Request)
}
type PrefixSuffixWorker struct {
	id      int
	prefixS string
	suffixS string
}
func (w *PrefixSuffixWorker) LaunchWorker(in chan Request) {
	w.prefix(w.append(w.uppercase(in)))
}
func (w *PrefixSuffixWorker) uppercase(in <-chan Request) <-chan Request {
	out := make(chan Request)
	go func() {
		for msg := range in {
			s, ok := msg.Data.(string)
			if !ok {
				msg.Handler(nil)
				continue
			}
			msg.Data = strings.ToUpper(s)
			out <- msg
		}
		close(out)
	}()
	return out
}
func (w *PrefixSuffixWorker) append(in <-chan Request) <-chan Request {
	out := make(chan Request)
	go func() {
		for msg := range in {
			uppercaseString, ok := msg.Data.(string)
			if !ok {
				msg.Handler(nil)
				continue
			}
			msg.Data = fmt.Sprintf("%s%s", uppercaseString, w.suffixS)
			out <- msg
		}
		close(out)
	}()
	return out
}
func (w *PrefixSuffixWorker) prefix(in <-chan Request) {
	go func() {
		for msg := range in {
			uppercasedStringWithSuffix, ok := msg.Data.(string)
			if !ok {
				msg.Handler(nil)
				continue
			}
			msg.Handler(fmt.Sprintf("%s%s", w.prefixS, uppercasedStringWithSuffix))
		}
	}()
}package main
import (
	"fmt"
	"log"
	"sync"
)
type Request struct {
	Data    interface{}
	Handler RequestHandler
}
type RequestHandler func(interface{})
func NewStringRequest(s string, wg *sync.WaitGroup) Request {
	myRequest := Request{
		Data: s,
		Handler: func(i interface{}) {
			defer wg.Done()
			s, ok := i.(string)
			if !ok {
				log.Fatal("Invalid casting to string")
			}
			fmt.Println(s)
		},
	}
	return myRequest
}
func main() {
	bufferSize := 100
	dispatcher := NewDispatcher(bufferSize)
	workers := 3
	for i := 0; i < workers; i++ {
		w := &PrefixSuffixWorker{
			prefixS: fmt.Sprintf("WorkerID: %d -> ", i),
			suffixS: " World",
			id:      i,
		}
		dispatcher.LaunchWorker(w)
	}
	requests := 10
	var wg sync.WaitGroup
	wg.Add(requests)
	for i := 0; i < requests; i++ {
		req := NewStringRequest(fmt.Sprintf("(Msg_id: %d) -> Hello", i), &wg)
		dispatcher.MakeRequest(req)
	}
	dispatcher.Stop()
	wg.Wait()
}반응형
    
    
    
  LIST
    'Go' 카테고리의 다른 글
| [Algorithms] 지식 표현(Knowledge Representation) (0) | 2022.12.06 | 
|---|---|
| [Algorithms] 탐색(Search) (0) | 2022.12.06 | 
| [Design Pattern] 중재인(Mediator), 관찰자(Observer), 장벽(Barrier) 패턴 (0) | 2022.11.30 | 
| [Design Pattern] 인터프리터(Interpreter), 방문자(Visitor), 상태(State) 패턴 (0) | 2022.11.30 | 
| [Design Pattern] 커맨드(Command), 템플릿(Template), 메멘토(Memento) 패턴 (0) | 2022.11.29 |