Dmitry Telenkov 10 小时之前
父节点
当前提交
4f745653be

+ 43 - 0
go/habr/after.go

@@ -0,0 +1,43 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+var start time.Time
+
+func init() {
+	start = time.Now()
+}
+
+func service1(c chan string) {
+	time.Sleep(3 * time.Second)
+	c <- "Hello from service 1"
+}
+
+func service2(c chan string) {
+	time.Sleep(5 * time.Second)
+	c <- "Hello from service 2"
+}
+
+func main() {
+	fmt.Println("main() started", time.Since(start))
+
+	chan1 := make(chan string)
+	chan2 := make(chan string)
+
+	go service1(chan1)
+	go service2(chan2)
+
+	select {
+	case res := <-chan1:
+		fmt.Println("Response from service 1", res, time.Since(start))
+	case res := <-chan2:
+		fmt.Println("Response from service 2", res, time.Since(start))
+	case <-time.After(2 * time.Second):
+		fmt.Println("No response received", time.Since(start))
+	}
+
+	fmt.Println("main() stopped", time.Since(start))
+}

+ 26 - 0
go/habr/channel_nil.go

@@ -0,0 +1,26 @@
+package main
+
+import (
+	"fmt"
+)
+
+func service(c chan string) {
+	c <- "responce"
+}
+
+func main() {
+	fmt.Println("main() started")
+
+	var chan1 chan string
+
+	go service(chan1)
+
+	select {
+	case res := <-chan1:
+		fmt.Println("Response from chan1", res)
+	default:
+		fmt.Println("No response")
+	}
+
+	fmt.Println("main() stopped")
+}

+ 72 - 0
go/habr/select.go

@@ -0,0 +1,72 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+var start time.Time
+
+func init() {
+	fmt.Println("init...")
+	start = time.Now()
+}
+
+func service1(c chan string) {
+	// time.Sleep(3 * time.Second)
+	fmt.Println("service1() started", time.Since(start))
+	c <- "Hello from service 1"
+}
+
+func service2(c chan string) {
+	// time.Sleep(5 * time.Second)
+	fmt.Println("service2() started", time.Since(start))
+	c <- "Hello from service 2"
+}
+
+func main() {
+	selectTest()
+	/*
+		fmt.Println("main() started", time.Since(start))
+
+		chan1 := make(chan string)
+		chan2 := make(chan string)
+
+		go service1(chan1)
+		go service2(chan2)
+
+		select {
+		case res := <-chan1:
+			fmt.Println("Response from service 1", res, time.Since(start))
+		case res := <-chan2:
+			fmt.Println("Response from service 2", res, time.Since(start))
+		}
+
+		fmt.Println("main() stopped", time.Since(start))
+	*/
+}
+
+func selectTest() {
+	fmt.Println("main() started", time.Since(start))
+
+	chan1 := make(chan string)
+	chan2 := make(chan string)
+
+	go service1(chan1)
+	go service2(chan2)
+
+	// С этой функций в select выполнится один из кейсов
+	// Без задержки будет выполнен default
+	// time.Sleep(1 * time.Second)
+
+	select {
+	case res := <-chan1:
+		fmt.Println("Response from service 1", res, time.Since(start))
+	case res := <-chan2:
+		fmt.Println("Response from service 2", res, time.Since(start))
+		// default:
+		// fmt.Println("No responce received", time.Since(start))
+	}
+
+	fmt.Println("main() stopped", time.Since(start))
+}

+ 126 - 0
go/habr/two_goroutine.go

@@ -0,0 +1,126 @@
+package main
+
+import (
+	"fmt"
+)
+
+// -----------------------------------------------------------------
+// Работа с несколькими горутинами
+
+func square(c chan int) {
+	fmt.Println("[square] reading")
+	num := <-c
+	c <- num * num
+}
+
+func cube(c chan int) {
+	fmt.Println("[cube] reading")
+	num := <-c
+	c <- num * num * num
+}
+
+func main() {
+	// unidirectonalChannel()
+
+	// anonymousGoroutine()
+
+	channelChannel()
+	/*
+		fmt.Println("[main] main() started")
+
+		squareChan := make(chan int)
+		cubeChan := make(chan int)
+
+		go square(squareChan)
+		go cube(cubeChan)
+
+		testNum := 3
+		fmt.Println("[main] sent testNum to squareChan")
+
+		squareChan <- testNum
+
+		fmt.Println("[main] resuming")
+		fmt.Println("[main] sent testNum to cubeChan")
+
+		cubeChan <- testNum
+
+		fmt.Println("[main] resuming")
+		fmt.Println("[main] reading from channels")
+
+		squareVal, cubeVal := <-squareChan, <-cubeChan
+		sum := squareVal + cubeVal
+
+		fmt.Println("[main] sum of square and cube of", testNum, " is", sum)
+		fmt.Println("[main] main() stopped")
+	*/
+}
+
+// -----------------------------------------------------------------
+// Однонаправленные каналы
+
+func greet(roc <-chan string) {
+	fmt.Println("Hello " + <-roc + "!")
+
+	// Это приведет к ошибке
+	// roc <- "qwerty"
+}
+
+func unidirectonalChannel() {
+	/*
+		roc := make(<-chan int)
+		soc := make(chan<- int)
+
+		fmt.Printf("Data type of roc `%T`\n", roc)
+		fmt.Printf("Data type of roc `%T`\n", soc)
+	*/
+
+	fmt.Println("main() started")
+	c := make(chan string)
+
+	go greet(c)
+
+	c <- "John"
+	fmt.Println("main() stopped")
+}
+
+// -----------------------------------------------------------------
+// Анонимные горутины
+
+func anonymousGoroutine() {
+	fmt.Println("main() started")
+	c := make(chan string)
+
+	// launch anonymous goroutine
+	go func(c chan string) {
+		fmt.Println("Hello " + <-c + "!")
+	}(c)
+
+	c <- "John"
+	fmt.Println("main() stopped")
+}
+
+// -----------------------------------------------------------------
+// Канал с типом данных канала.
+// Канал - объкт первого класса.
+
+// gets a channels and writes a channel to it
+func greeter(cc chan chan string) {
+	c := make(chan string)
+	cc <- c
+}
+
+func channelChannel() {
+	fmt.Println("main() started")
+
+	cc := make(chan chan string)
+
+	go greeter(cc) // start `greeter` goroutine using `cc` channel
+
+	c := <-cc
+
+	go greet(c)
+
+	c <- "John"
+
+	fmt.Println("main() stopped")
+}

+ 30 - 0
go/habr/waitgroup.go

@@ -0,0 +1,30 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+)
+
+func service(wg *sync.WaitGroup, instance int) {
+	time.Sleep(2 * time.Second)
+	fmt.Println("Service called on instance", instance)
+	wg.Done()
+}
+
+func main() {
+	wgExample()
+}
+
+func wgExample() {
+	fmt.Println("main() started")
+	var wg sync.WaitGroup
+
+	for i := 1; i <= 3; i++ {
+		wg.Add(1) // increment counter
+		go service(&wg, i)
+	}
+
+	wg.Wait() // blocks here
+	fmt.Println("main() stopped")
+}

+ 19 - 12
go/stepik/3/blocking.go

@@ -4,23 +4,13 @@ import (
 	"fmt"
 )
 
-func main() {
-	c := make(chan int)
-	quit := make(chan int)
-	go func() {
-		for i := 0; i < 10; i++ {
-			fmt.Println(<-c)
-		}
-		quit <- 0
-	}()
-	fibonacci(c, quit)
-}
-
 func fibonacci(c, quit chan int) {
 	x, y := 0, 1
 	for {
+		// Пишет в канал пока не поямает quit
 		select {
 		case c <- x:
+			fmt.Println("write to channel")
 			x, y = y, x+y
 		case <-quit:
 			fmt.Println("quit")
@@ -28,3 +18,20 @@ func fibonacci(c, quit chan int) {
 		}
 	}
 }
+
+func main() {
+	c := make(chan int)
+	quit := make(chan int)
+
+	// пытается 10 раз считать из канала
+	go func() {
+		for i := 0; i < 10; i++ {
+			fmt.Println("Want to read from channel `c`")
+			fmt.Println(<-c)
+		}
+		quit <- 0
+	}()
+
+	fmt.Println("Call fibonacci")
+	fibonacci(c, quit)
+}

+ 22 - 0
go/stepik/3/channel_task.go

@@ -0,0 +1,22 @@
+package main
+
+import (
+	"fmt"
+)
+
+func work() {
+	fmt.Println("Tt's function work")
+}
+
+func main() {
+	done := make(chan struct{})
+
+	go func(d chan struct{}) {
+		work()
+		close(d)
+	}(done)
+
+	<-done
+
+	fmt.Println("Function main() was finished")
+}

+ 27 - 0
go/stepik/3/mutex.go

@@ -0,0 +1,27 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+)
+
+func main() {
+	var x int
+	wg := new(sync.WaitGroup)
+	mu := new(sync.Mutex)
+
+	for i := 0; i < 1000; i++ {
+		// Запускаем 1000 экземпляров горутины, увеличивающей счетчик на 1
+		wg.Add(1)
+		go func(wg *sync.WaitGroup) {
+			defer wg.Done()
+			mu.Lock()
+			x++
+			mu.Unlock()
+		}(wg)
+	}
+
+	wg.Wait()
+
+	fmt.Println(x)
+}

+ 44 - 0
go/stepik/3/sleepy_gopher.go

@@ -0,0 +1,44 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+func init() {
+	rand.Seed(time.Now().Unix())
+}
+
+func SleepyGopher(id int, c chan int) {
+	duration := time.Duration(rand.Intn(4000)) * time.Millisecond
+	fmt.Printf("gopher %d sleep for %v\n", id, duration)
+	time.Sleep(duration)
+	c <- id
+}
+
+func main() {
+	timeout := time.After(2 * time.Second)
+
+	c := make(chan int, 5)
+
+	/**
+	Горутины для гоферов нужно создать заранее. Если делать это в for
+	с select, то select будет блокировать дальнейшее исполнение и
+	создание следующей горутины
+	**/
+
+	for i := 0; i < 5; i++ {
+		go SleepyGopher(i, c)
+	}
+
+	for i := 0; i < 5; i++ {
+		select {
+		case gopherID := <-c: // Ждет пока проснется гофер
+			fmt.Println("gopher: ", gopherID, "has finished sleeping")
+		case <-timeout: // Ждет окончания времени
+			fmt.Println("my patience ran out\n")
+			return
+		}
+	}
+}

+ 47 - 0
go/stepik/3/sync.go

@@ -0,0 +1,47 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+)
+
+func work() {
+	fmt.Println("It's function `work()`")
+}
+
+func main() {
+	wg := new(sync.WaitGroup)
+
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func(wg *sync.WaitGroup) {
+			defer wg.Done()
+			work()
+		}(wg)
+	}
+
+	wg.Wait()
+
+	fmt.Println("End")
+}
+
+/*
+func main() {
+	wg := new(sync.WaitGroup)
+
+	for i := 0; i < 5; i++ {
+		wg.Add(1)
+		go work(i, wg)
+	}
+
+	wg.Wait()
+	fmt.Println("Горутины завершили выполнение")
+}
+
+func work(id int, wg *sync.WaitGroup) {
+	defer wg.Done()
+	fmt.Printf("Горутина %d начала выполнение \n", id)
+	time.Sleep(2 * time.Second)
+	fmt.Printf("Горутина %d завершила выполнение \n", id)
+}
+*/

+ 119 - 0
go/stepik/3/timer.go

@@ -0,0 +1,119 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+)
+
+// программа засыпает на заданное время
+// time.Sleep(time.Second * 2)
+
+// func After(d Duration) <-chan Time
+// создает канал, который через заданное время вернет значение
+//timer := time.After(time.Second)
+//<-timer // значение будет получено из канала ровно через 1 секунду
+
+// func Tick(d Duration) <-chan Time
+// создает канал, который будет посылать сигналы постоянно через
+// заданный промежуток времени
+
+/*
+ticker := time.Tick(time.Second)
+count := 0
+
+for {
+	<-ticker
+	fmt.Println("очередной тик")
+	count++
+	if count == 3 {
+		break
+	}
+}
+*/
+
+// ---------------------------------------------------------------
+
+// type Timer
+
+// Таймер по своей сути очень похож на результат работы After, но
+// позволяет остановить или изменить время его выполнения:
+
+// создаем новый таймер, который сработает через 1 секунду
+/*
+t := time.NewTimer(time.Second)
+
+fo func() {
+	<-t.C // C - канал, который должен вернуть значение через заданное время
+}()
+t.Stop()
+*/
+
+// пока таймер не сработал, мы может сбросить его, установив новый
+// срок выполнения
+// t.Reset(time.Second * 2)
+// <-t.C
+
+// ---------------------------------------------------------------
+
+// type Ticker
+
+// Ticker же работает как функция Tick, но может быть остановлен:
+/*
+func NewTicker(d Duration) *Ticker // создаем новый Ticker
+func (t *Ticker) Stop() // останавливаем Ticker
+*/
+
+func main() {
+	// <-work()
+
+	tick := time.NewTicker(time.Second)
+	defer tick.Stop()
+
+	wg := new(sync.WaitGroup)
+
+	for i := 1; i <= 5; i++ {
+		wg.Add(1)
+		go worker(i, tick.C, wg)
+	}
+
+	wg.Wait()
+}
+
+func work() <-chan struct{} {
+	done := make(chan struct{}) // канал для синхронизации горутин
+
+	go func() {
+		// синхронизирующий канал будет закрыт,
+		// когда функция завершит свою работу
+		defer close(done)
+
+		stop := time.NewTimer(time.Second)
+
+		tick := time.NewTicker(time.Millisecond * 200)
+		// освободим ресурсы, при завершении работы функции
+		defer tick.Stop()
+
+		for {
+			select {
+			case <-stop.C:
+				// stop - Timer, который через 1 секунду даст
+				// сигнал завершить работу
+				return
+			case <-tick.C:
+				// tick -Ticker, посылающий сигнал выполнить
+				// работу каждые 200 миллисекунд
+				fmt.Println("тик-так")
+			}
+		}
+	}()
+
+	return done
+}
+
+func worker(id int, limit <-chan time.Time, wg *sync.WaitGroup) {
+	defer wg.Done()
+	<-limit
+	fmt.Printf("worker %d выполнил работу\n", id)
+
+}

+ 106 - 0
go/stepik/4/list.go

@@ -0,0 +1,106 @@
+package main
+
+import (
+	"container/list"
+	"fmt"
+)
+
+func printList(l *list.List) {
+	for temp := l.Front(); temp != nil; temp = temp.Next() {
+		fmt.Printf("%v ", temp.Value)
+	}
+}
+
+func main() {
+
+	// foo1()
+	foo2()
+
+	/*
+	   mylist := list.New()
+
+	   mylist.PushBack(0)
+	   mylist.PushBack(1)
+	   mylist.PushBack(2)
+	   mylist.PushBack(3)
+
+	   // Получаем указатель на элемент который добавили (*Element)
+	   elem3 := mylist.PushBack(4)
+	   printList(mylist)
+
+	   // удаляем элемент '3' по указателю (*Element)
+	   mylist.Remove(elem3)
+
+	   // так же можем воспользоваться методом Front()/Back() чтобы
+	   // получить первый/последний элемент
+	   mylist.Remove(mylist.Front())
+	   fmt.Printf("\nПосле удаления\n")
+	   printList(mylist)
+
+	   	// mylist.PushFront(1)
+	   	// mylist.PushFront(2)
+	   	// mylist.PushFront(3)
+	*/
+}
+
+func foo1() {
+	// Создаем контейнер list и добавляем в него элементы
+	mylist := list.New()
+	mylist.PushBack(2)
+	mylist.PushBack(5)
+	mylist.PushBack(3)
+	mylist.PushBack(11)
+	mylist.PushBack(12)
+
+	// Проходимся по элементам и удаляем те, которые меньше 10
+	for e := mylist.Front(); e != nil; {
+		// Запоминаем следующий элемент перед удалением текущего
+		next := e.Next()
+		if e.Value.(int) < 10 {
+			// Удалялем текущий элемент из списка
+			mylist.Remove(e)
+		}
+		e = next // Переходим к следующему элементу
+	}
+
+	// Выводим список после удаления элементов
+	for e := mylist.Front(); e != nil; e = e.Next() {
+		fmt.Println(e.Value)
+	}
+}
+
+// ---------------------------------------------------------------
+
+func foo2() {
+	queue := list.New()
+	Push(1, queue)
+	Push(2, queue)
+	Push(3, queue)
+
+	printQueue(queue)
+	Pop(queue)
+	printQueue(queue)
+	// fmt.Println(Pop(queue))
+
+	// printQueue(queue)
+}
+
+// Добавление элементов в очередь
+func Push(elem interface{}, queue *list.List) {
+	queue.PushBack(elem)
+}
+
+// Удуление элемента и его возврат
+func Pop(queue *list.List) interface{} {
+	if queue.Front() != nil {
+		return nil
+	}
+	return queue.Remove(queue.Front())
+}
+
+// Печать очереди в одну строку без пробелов
+func printQueue(queue *list.List) {
+	for temp := queue.Front(); temp != nil; temp = temp.Next() {
+		fmt.Print(temp.Value)
+	}
+}