golang [去阻塞频道]与Go#golang,#go,#go channels,#go synchronization,#goroutines,#waitgroups中的频道同步和阻止,

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang [去阻塞频道]与Go#golang,#go,#go channels,#go synchronization,#goroutines,#waitgroups中的频道同步和阻止,相关的知识,希望对你有一定的参考价值。

package main

import (
	"fmt"
	"os"
	"strings"
	"sync"
)

func main() {
	devNull, _ := os.Create(os.DevNull) // Operating System's /dev/null
	out := make(chan string)

	// WaitGroup is used for thread synchronization. As long as there is
	// > 0 waiters on this group, goroutine calling wg.Wait() is going to
	// be blocked.
	// wg.Wait() is the last call in this example, before main() returns.
	wg := sync.WaitGroup{}

	wg.Add(1) // Add waiter to wait group

	go func(c chan string) <-chan string {
		fromStdIn := make([]byte, 1024) // 1K buffer
		for true {                      // Effectively infinite loop, but Go does not complain
			if n, _ := os.Stdin.Read(fromStdIn); n > 0 {
				c <- string(fromStdIn[:n-1]) // Trim empty part of buffer
			}
		}
		close(c) // We do not necessarily need to close this if we
		// expect the program to run indefinitely.
		return c
	}(out)

	go func() {
		for {
			select {
			// This case blocks the main thread, but prevents the program
			// from running away with the CPU like a bandit.
			case v := <-out:
				if strings.Compare(v, "quit") == 0 {
					fmt.Printf("Quitting...\n")
					wg.Done() // Decrement wg, reducing count to 0
				} else {
					fmt.Fprintf(devNull, "%s", v)
				}
			}
		}
	}()

	// As long is waiters > 0, thread does not return.
	wg.Wait()
}
package main

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

const TIMEOUT = 20

// someSlowFunction simulates a function that has undefined
// runtime.
func someSlowFunction(n int) int64 {
	before := time.Now().UnixNano()
	// Inject randomness, to simulate unknown runtime
	time.Sleep(time.Duration(rand.Intn(10)*n) * time.Second)
	return time.Now().UnixNano() - before // Return delta time
}

func main() {
	out := make(chan int64, 10)
	// Setup a 10 second time as a means to limiting runtime to 10 seconds
	done := time.NewTimer(TIMEOUT * time.Second).C

	// Consume a "slow" function and lean on select to
	go func(f func(n int) int64, c chan int64) <-chan int64 {
		defer close(c)
		for i := 0; i < 10; i++ {
			c <- f(i) // Map f over values of i
		}
		return c
	}(someSlowFunction, out)

	go func() {
		for i := 0; i < 10; i++ {
			result := <-out
			fmt.Printf("Elapsed=%d(ns)\n", result)
		}
	}()

	<-done
	fmt.Printf("Timeout\n")
}

// 	for {
// 		// Select will block as long as neither channel is ready.
// 		// the done channel will become ready when the timer expires
// 		// and will result in main returning as soon as timer is triggered,
// 		// even if the out channel is still receiving data.
// 		select {
// 		case result := <-out:
// 			fmt.Printf("Elapsed=%d(ns)\n", result)
// 		case <-done:
// 			fmt.Printf("Timeout\n")
// 			return
// 		}
// 	}
// }
package main

import (
	"fmt"
	"os"
)

func main() {
	devNull, _ := os.Create(os.DevNull) // Operating System's /dev/null
	out := make(chan int)
	go func(c chan int) <-chan int {
		fromStdIn := make([]byte, 1024) // 1K buffer
		for true {                      // Effectively infinite loop, but Go does not complain
			if n, _ := os.Stdin.Read(fromStdIn); n > 0 {
				c <- n // Put number of chars read onto channel
			}
		}
		close(c) // We do not necessarily need to close this if we
		// expect the program to run indefinitely.
		return c
	}(out)

	for {
		select {
		// This case blocks the main thread, but prevents the program
		// from running away with the CPU like a bandit.
		case v := <-out:
			fmt.Fprintf(devNull, "%d", v)
			// If this default case were (un)commented, it would end-up
			// being selected vast amount of time, resulting in effectively
			// no actual work being done, resulting in baking the CPU.
			// if return were (un)commented the for loop would
			// immediately terminate since the channel starts out empty,
			// resulting in select choosing the default case, and returning.
			//
			// Values are placed onto the channel as the input from
			// stdin is consumed by the program.
			//
			// default:
			// return
		}
	}
}
package main

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

type callbackFun func(n int) bool

// cbHandlerFun receives callback functions via a channel
// as well as values and executes callbacks with given value,
// reporting result of each call.
func cbHandlerFun(ch <-chan callbackFun, r <-chan int) {
	var numTrue, numFalse int
	for {
		f := <-ch
		if f(<-r) {
			numTrue++
		} else {
			numFalse++
		}
		fmt.Printf("True(s)=%d False(s)=%d\n", numTrue, numFalse)
	}
}

// timerFun implements a basic timeout routine, which could be
// used as a means of a Sleep alternative.
func timerFun() <-chan time.Time {
	// Create and return a timer channel which the main
	// thread will block on, until timer fires.
	done := time.NewTimer(5 * time.Second).C
	return done
}

func workFun(ch chan<- callbackFun, r chan<- int) {
	// Doing some work and then sending callbacks once work
	// is done.
	randomNumber := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
	r <- randomNumber.Intn(100)
	ch <- func(n int) bool {
		if n%2 == 0 {
			fmt.Printf("%d is even\n", n)
			return true
		}
		fmt.Printf("%d is odd\n", n)
		return false
	}
	r <- randomNumber.Intn(100)
	ch <- func(n int) bool {
		if n > 50 {
			fmt.Printf("%d is > 50\n", n)
			return true
		}
		fmt.Printf("%d is <= 50\n", n)
		return false
	}
}

func main() {
	ch := make(chan callbackFun, 10)
	results := make(chan int, 10)

	// Callback handler will remain resident and maintains
	// state internally for as long as the main thread is alive.
	go cbHandlerFun(ch, results)

	// If our task or tasks need to run in some perpetual loop,
	// we should encapsulate this part of the logic in a for loop.
	// The loop will block as it waits for work to happen in goroutines,
	// with channels used for synchronization and timeout handling.
	// We can use select in this instance as well, but we only need it if
	// some additional action is required after timeout is received.
	for {
		done := timerFun()
		workFun(ch, results)
		<-done // Blocks, waiting for data on this channel
	}
}

Golang✔️走进 Go 语言✔️ 第十七课 select & 超时和非阻塞

【Golang】✔️走进 Go 语言✔️ 第十七课 select & 超时和非阻塞

概述

Golang 是一个跨平台的新生编程语言. 今天小白就带大家一起携手走进 Golang 的世界. (第 17 课)

select

Select 是 Go 中的一个控制结构. 类似于 switch 语句. 如果没有 case 可运行, select 将会阻塞, 直到有 case 可以运行.

select 语法:

  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行, 它就执行, 忽略其他
  • 如果有多个 case 都可以运行, select 会随机挑出一个

例子:

 package main

import (
	"fmt"
	"time"
)

func main() {

	// 创建通道
	channel1 := make(chan string)
	channel2 := make(chan string)

	go func() {
		time.Sleep(time.Second)
		channel1 <- "1 号"
	}()

	go func() {
		time.Sleep(time.Second * 2)
		channel2 <- "2 号"
	}()

	// select
	for i := 0; i < 2; i++ {
		select {
		
		case msg1 := <- channel1:
			fmt.Println("received", msg1)
		
		case msg2 := <- channel2:
			fmt.Println("received", msg2)
		}
	}
	
}

输出结果:

received 1 号
received 2 号

超时

超时 (Timeout) 对于连接到外部资源或在不需要绑定执行时间的程序很重要.

例子:

package main

import (
	"fmt"
	"time"
)

func main() {

	// 创建通道
	channel1 := make(chan string)

	// 协程
	go func() {
		time.Sleep(time.Second * 5)
		channel1 <- "1 号"
	}()

	// select
	select {
	
	case msg1 := <-channel1:
		fmt.Println(msg1)
	
	case <-time.After(time.Second * 3):
		fmt.Println("timeout")
	}
	
}

输出结果:

timeout

非阻塞

通道的如果同时发送和接收就会阻塞. 但是, 可以使用 select 和 default 字句来实现非阻塞发送, 接收. 也可以实现非阻塞多路通信.


例子:

package main

import "fmt"

func main() {

	// 创建缓冲通道, 如果不加缓冲, 都会选择defalut
	message := make(chan string, 1)

	// 接收
	select {

	case msg := <- message:
		fmt.Println("收到消息: ", msg)

	default:
		fmt.Println("没有收到消息")
	}

	// 发送
	select {

	case message <- "hello world":
		fmt.Println("send message")

	default:
		fmt.Println("no message")
	}

	// 接收
	select {

	case msg := <- message:
		fmt.Println("收到消息: ", msg)

	default:
		fmt.Println("没有收到消息")
	}

}

输出结果:

没有收到消息
send message
收到消息 hello world

以上是关于golang [去阻塞频道]与Go#golang,#go,#go channels,#go synchronization,#goroutines,#waitgroups中的频道同步和阻止,的主要内容,如果未能解决你的问题,请参考以下文章

Golang✔️走进 Go 语言✔️ 第十七课 select & 超时和非阻塞

Golang✔️走进 Go 语言✔️ 第十七课 select & 超时和非阻塞

Golang 阻塞和非阻塞

在 go 中输入不可知的频道

Golang网络库中socket阻塞调度源码剖析

Golang网络库中socket阻塞调度源码剖析