go 语法
2022年1月11日常量递增赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
const ( Monday = 1 + iota Tuesday Wednesday ) const ( Readable = 1 << iota //0001 Writable //0010 Executable //0100 ) /** * int&int 两个值的高位数相同,你这里有1我这里也有1, 返回会原值, 不同返回0 * int&^int 用第二值的高位数减去第一个值的高位数, 有就减去, */ func TestBitClear(t *testing.T) { a := 15 //0111 a = a &^ Readable t.Log(a) a = a &^ Executable t.Log(a) t.Log(a&Readable == Readable, a&Writable == Writable, a&Executable == Executable) } |
数据类型 注意不支持隐性转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 byte rune //uint8 的别名 float32 float64 complex64 complex128 |
变量声明
1 2 3 4 5 6 7 8 9 10 |
/** * 相同长度的可以比较 */ func TestCompareArray(t *testing.T) { a := [...]int{1, 2, 3, 4} //不定长声明 b := [...]int{1, 3, 2, 4} d := [...]int{1, 2, 3, 4} t.Log(a == b) t.Log(a == d) } |
switch 可以写表达式 可以写多个值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
func TestSwitchMultiCase(t *testing.T) { for i := 0; i < 5; i++ { switch i { case 0, 2: t.Log("Even") case 1, 3: t.Log("Odd") default: t.Log("it is not 0-3") } } } func TestSwitchCaseCondition(t *testing.T) { for i := 0; i < 5; i++ { switch { case i%2 == 0: t.Log("Even") case i%2 == 1: t.Log("Odd") default: t.Log("unknow") } } } |
循环 START循环 矛点循环 矛点必须在跳转前
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func TestWhileLoop(t *testing.T) { //按表达式循环 n := 0 for n < 5 { t.Log(n) n++ } //无限循环 for { t.Log("无线循环") } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package main import "fmt" func main() { // 1: for i := 0; i < 15; i++ { fmt.Printf("The counter is at %d\n", i) } // 2: i := 0 START: fmt.Printf("The counter is at %d\n", i) i++ if i < 15 { goto START } } |
1 2 3 4 5 6 7 8 9 10 |
ZF1: for i := 0; i <= 5; i++ { for j := 0; j <= 5; j++ { if j == 4 { continue ZF1 } fmt.Printf("i is: %d, and j is: %d\n", i, j) } } } |
数组声明遍历数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
func TestArrayTravel(t *testing.T) { var arr [3]int //声明一个长度为3 数组里面装int,没有赋值 arr1 := [4]int{1, 2, 3, 4} //声明一个长度为4 数组里面装int,提前赋值的 arr2 := []int{} //未定义数组 arr3 := [...]int{1, 3, 4, 5} //定长数组 year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} t.Log(len(arr1), cap(year)) //获取长度, 获取存储空间 t.Log(len(arr1), cap(arr2)) //获取长度, 获取存储空间 t.Log(arr[2]) t.Log(arr1[1:4]) //数组截取 t.Log(arr1[1:]) //数组截取 t.Log(arr1[:3]) //数组截取 arr2 = append(arr2, 1, 2, 3) t.Log(arr2) //数组截取 for i := 0; i < len(arr3); i++ { t.Log(arr3[i]) } for k, v := range arr3 { t.Log(k, v) } } |
map的使用
1 2 3 4 5 6 7 8 9 10 11 12 |
func TestInitMap(t *testing.T) { m1 := map[int]int{1: 1, 2: 4, 3: 9} m2 := map[int]int{} m3 := make(map[int]int, 10) m4 := map[string]string{"k1": "v1", "k2": "v2"} m2[4] = 16 t.Logf("len m1=%d", m1) t.Logf("len m2=%d", m2) t.Logf("len m3=%d", m3) t.Log(m4) } |
字符串变数组 数组变字符串
1 2 3 4 5 6 7 8 |
func TestStringFn(t *testing.T) { s := "A,B,C" parts := strings.Split(s, ",") for _, part := range parts { t.Log(part) } t.Log(strings.Join(parts, "-")) } |
随机数 , 记得添加rand.Seed(time.Now().UnixNano())
要不然一直都是固定的数值
1 2 3 4 |
func returnMultiValues() (int, int) { rand.Seed(time.Now().UnixNano()) return rand.Intn(10), rand.Intn(20) } |
函数 不通过return 返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package main import "fmt" func main() { var min, max int min, max = MinMax(78, 65) fmt.Printf("Minmium is: %d, Maximum is: %d\n", min, max) } func MinMax(a int, b int) (min int, max int) { if a < b { min = a max = b } else { min = b max = a } return } |
函数外部参数返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package main import ( "fmt" ) // this function changes reply: func Multiply(a, b int, reply *int) { *reply = a * b } func main() { n := 0 reply := &n Multiply(10, 5, reply) fmt.Println("Multiply:", *reply) // Multiply: 50 } |
函数传递长参
1 2 |
func Greeting(prefix string, who ...string) Greeting("hello:", "Joe", "Anna", "Eileen") |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package main import "fmt" func main() { x := min(1, 3, 2, 0) fmt.Printf("The minimum is: %d\n", x) slice := []int{7,9,3,5,1} x = min(slice...) fmt.Printf("The minimum in the slice is: %d", x) } func min(s ...int) int { if len(s)==0 { return 0 } min := s[0] for _, v := range s { if v < min { min = v } } return min } |
函数defer 和追踪 用了这个关键词,调用的函数会放到最后执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * 关闭文件流 */ defer file.Close() /** * 解锁一个加锁的资源 */ mu.Lock() defer mu.Unlock() /** * 打印最终报告 */ printHeader() defer printFooter() /** * 关闭数据库链接 */ defer disconnectFromDB() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package main import "fmt" func trace(s string) { fmt.Println("开始:", s) } func untrace(s string) { fmt.Println("结束:", s) } func a() { trace("a") defer untrace("a") fmt.Println("执行: a程序") } func b() { trace("b") defer untrace("b") fmt.Println("执行: a程序") a() } func main() { b() } |
go 方法调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
type IntConv func(op int) int //定义一个新的数据类型 func timeSpent(inner IntConv) IntConv { //返回一个方法 return func(n int) int { start := time.Now() //开始时间 ret := inner(n) //执行传入的方法 fmt.Println("time spent:", time.Since(start).Seconds()) //打印结束时间 return ret } } func slowFun(op int) int { time.Sleep(time.Second * 1) //休息一秒的 return op } func TestFn(t *testing.T) { tsSF := timeSpent(slowFun) //返回一个包装好的计时器方法 t.Log(tsSF(10)) //调用这个包装好的计时方法还可以传递参数 } |
数据类型实例时自动调用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * 定义一个新的数据结构 */ type Employee struct { Id string Name string Age int } /** * 数据示例会自动调用这个方法,转换数据结构 * 加 * 星号避免内存拷贝 */ func (e *Employee) String() string { fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) //查看内存地址 return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age) } func TestCreateEmployeeObj(t *testing.T) { e2 := new(Employee) //返回指针 fmt.Printf("Address is %x\n", unsafe.Pointer(&e2.Name)) t.Log(e2) //ID:-Name:-Age:0 t.Log("---------------------------------------------------------------------") e := Employee{"0", "Bob", 20} fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) t.Log(e) //{0 Bob 20} } |
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package interface_test import "testing" /** * 定义一个接口 */ type Programmer interface { WriteHelloWorld() string } /** * 定义一个实现 Programmer 接口的 数据结构, 实现就是首字母大写后面加接口名称 */ type GoProgrammer struct { Id string } /** * 开始通过 数据结构 实现 接口的方法 */ func (g *GoProgrammer) WriteHelloWorld() string { return "Hello World" } /** * 如何使用 */ func TestClient(t *testing.T) { var p Programmer //声明变量, 这个变量只能是接口这个结构 p = new(GoProgrammer) //我new一个数据结构, 这个数据结构,源自你这个接口 t.Log(p.WriteHelloWorld()) //调用数据结构, 实现的方法 } |
扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package extension import ( "fmt" "testing" ) /** * 定义一个数据结构 */ type Pet struct{} /** * 根据数据结构实现了Speak 方法 */ func (p *Pet) Speak() { fmt.Print("...") } /** * 根据数据结构实现了 SpeakTo方法 */ func (p *Pet) SpeakTo(host string) { p.Speak() fmt.Println(host) } /** * 定义了一个数据结构里面包含了 Pet 数据结构 * 包含的数据结构在这个数据结构中自动展开,里面的方法 */ type Dog struct { Pet } /** * 根据 Dog 数据结构实现了 Speck方法 * 后实现的方法,级别不如先前包含的级别高 */ func (d *Dog) Speak() { fmt.Print("Wang!") } func TestDog(t *testing.T) { dog := new(Dog) dog.SpeakTo("Chao") } |
interface接口类型的方法,可以传递任何数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package empty_interface import ( "fmt" "reflect" "strings" "testing" ) func DoSomething(p interface{}) { fmt.Println(reflect.TypeOf(p)) switch v := p.(type) { case int: fmt.Println("Integer", v) case string: fmt.Println("String", v) default: fmt.Println("Unknow Type", v) } } func TestEmptyInterfaceAssertion(t *testing.T) { DoSomething(10) DoSomething("10") DoSomething([...]int{1, 2, 3, 4}) DoSomething(map[string]string{"k1": "v1", "k2": "v2"}) DoSomething(strings.Split("A,B,C", ",")) } |
接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package polymorphism import ( "fmt" "testing" ) /** * 定义数据类型 */ type Code string /** * 定义接口 */ type Programmer interface { WriteHelloWorld() Code } /** * 定义数据结构 */ type GoProgrammer struct { } /** * 根据结构实现接口 */ func (p *GoProgrammer) WriteHelloWorld() Code { return "fmt.Println(\"Hello World!\")" } /** * 定义一个数据结构 */ type JavaProgrammer struct { } /** * 实现这个结构 */ func (p *JavaProgrammer) WriteHelloWorld() Code { return "System.out.Println(\"Hello World!\")" } /** * 这个数据结构必须来自接口 */ func writeFirstProgram(p Programmer) { fmt.Printf("%T %v\n", p, p.WriteHelloWorld()) } func TestPolymorphism(t *testing.T) { goProg := &GoProgrammer{} //通过寻址声明 writeFirstProgram(goProg) javaProg := new(JavaProgrammer) //通过new声明 writeFirstProgram(javaProg) } |
错误处理
- panic 用于不可恢复的错误
- panic 退出前会执行defer指定的内容
- os.Exit 退出时不会调用defer指定的函数
- os.Exit 退出时不会输出当前调用栈信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
package err_test import ( "errors" "fmt" "testing" ) var LessThanTwoError = errors.New("n should be not less than 2") //定义一个错误 var LargerThenHundredError = errors.New("n should be not larger than 100") //定义一个错误 /** * go 写程序第二个方法就是错误信息 */ func GetFibonacci(n int) ([]int, error) { if n < 2 { return nil, LessThanTwoError } if n > 100 { return nil, LargerThenHundredError } fibList := []int{1, 1} for i := 2; i < n; i++ { fibList = append(fibList, fibList[i-2]+fibList[i-1]) } return fibList, nil } func TestGetFibonacci(t *testing.T) { if v, err := GetFibonacci(1); err != nil { if err == LessThanTwoError { fmt.Println("It is less.") } t.Error(err) } else { t.Log(v) } } |
panic 和 os.Exit 的比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package panic_recover import ( "fmt" "testing" ) func TestPanicVxExit(t *testing.T) { defer func() { if err := recover(); err != nil { fmt.Println("panic 报错会调用这里的方法", err) } }() fmt.Println("Start") //panic(errors.New("Something wrong!")) //os.Exit(-1) //fmt.Println("End") } |
go 协程机制 , 线程 和 协程, 协程是更轻量的线程
- 创建时默认的stack的大小
- jdk5以后 java thread stack 默认为1M
- Groutine 的 stack 初始化为2K
- 和KSE (Kernel Space Entity) 的对应关系
- java Thread 是1:1
- Groutine是M:N
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package groutine_test import ( "fmt" "testing" "time" ) func TestNoGroutine(t *testing.T) { for i := 0; i < 10; i++ { fmt.Println(i) } time.Sleep(time.Millisecond * 50) } func TestGroutine(t *testing.T) { for i := 0; i < 10; i++ { //让代码在协程里运行, 协程是多核对多任务 go func(i int) { fmt.Println(i) }(i) //需要传递下for i } time.Sleep(time.Millisecond * 50) } |
共享内存并发机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
package share_mem import ( "sync" "testing" "time" ) /** * 运行下面代码可以看出counter的结果不是5000 * 是因为有多个协程同时对他进行操作,而导致的 */ func TestCounter(t *testing.T) { counter := 0 for i := 0; i < 5000; i++ { go func() { counter++ }() } time.Sleep(1 * time.Second) //为了避免协程的速度超过进程的速度所以先加上 t.Logf("counter = %d", counter) } /** * 下面代码可以看出运行结果是 5000 但是协程的速度还是超过了进程的速度 * */ func TestCounterThreadSafe(t *testing.T) { var mut sync.Mutex //声明变量类型 counter := 0 for i := 0; i < 5000; i++ { go func() { defer func() { mut.Unlock() }() //异常情况下解锁, mut.Lock() //协程运行时锁,不让其他协程进来 counter++ }() } time.Sleep(1 * time.Second) //为了避免协程的速度超过进程的速度所以先加上 t.Logf("counter = %d", counter) } /** * 解决协程还没结束, 进程已经结束, * 一个好的协程需要有等待, 和锁 */ func TestCounterWaitGroup(t *testing.T) { var mut sync.Mutex //声明变量类型 var wg sync.WaitGroup //声明变量类型 counter := 0 for i := 0; i < 5000; i++ { wg.Add(1) go func() { defer func() { mut.Unlock() }() //异常情况解锁 mut.Lock() //上锁 counter++ wg.Done() //通知进程可以开始了 }() } wg.Wait() //让进程等待 t.Logf("counter = %d", counter) } |
CSP并发机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package concurrency import ( "fmt" "testing" "time" ) /** * 定义一个方法返回字符串的方法 */ func service() string { time.Sleep(time.Millisecond * 50) return "service 返回值" } /** * 定义一个打印方法 */ func otherTask() { fmt.Println("otherTask 开始") time.Sleep(time.Millisecond * 100) fmt.Println("otherTask 结束") } /** * 调用 service 和 otherTask */ func TestService(t *testing.T) { fmt.Println(service()) otherTask() } func AsyncService() chan string { //retCh := make(chan string) //创建一个 chan 数据中转站 retCh := make(chan string, 10) //创建一个数据中转站 加1代表不等待<-retCh被接收直接往下运行, 还代表大小 go func() { fmt.Println("AsyncService go 开始") retCh <- service() //返回给retCh, 当结果返回给retCh, 才会执行打印, 所以otherTask虽然在后, 但是打印在前 fmt.Println("AsyncService go 结束") }() return retCh } func TestAsynService(t *testing.T) { retCh := AsyncService() otherTask() fmt.Println(<-retCh) //返回给然后打印 } |
多路选择和超时控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package select_test import ( "fmt" "testing" "time" ) /** * 定义一个需要一定时间才会返回结果的方法 */ func service(n int) string { time.Sleep(time.Duration(n * int(time.Millisecond))) return "完成" } /** * CSP 并发 */ func AsyncService(n int) chan string { retCh := make(chan string, 1) go func() { fmt.Println("AsyncService 开始.") retCh <- service(n) fmt.Println("AsyncService 结束.") }() return retCh } /* * 超时控制 */ func TestOvertime(t *testing.T) { select { case ret := <-AsyncService(1): //控制这里的参数如果超过了10秒 t.Log(ret) case <-time.After(time.Millisecond * 10): //就执行这里 t.Error("time out 30") } } /* * 多渠道选择, 这里多运行几次看结果, 至少10次 */ func TestSelect(t *testing.T) { select { case <-AsyncService(1): t.Log("使用渠道1") case <-AsyncService(1): t.Log("使用渠道2") } } |
channel的关闭和广播
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package channel_close import ( "fmt" "sync" "testing" ) /** * 创建 chan 数据 */ func dataProducer(ch chan int, wg *sync.WaitGroup) { go func() { for i := 0; i < 100; i++ { ch <- i } close(ch) //循环完毕后关闭ch wg.Done() //通知别等 }() } /** * 打印 chan 数据 */ func dataReceiver(ch chan int, wg *sync.WaitGroup, str string) { go func() { //无限循环 for { if data, ok := <-ch; ok { fmt.Println(data, str) } else { break } } wg.Done() //通知别等 }() } /** * 广播 */ func TestCloseChannel(t *testing.T) { var wg sync.WaitGroup ch := make(chan int) //创建一个chan wg.Add(1) dataProducer(ch, &wg) wg.Add(1) dataReceiver(ch, &wg, "接收者1") wg.Add(1) dataReceiver(ch, &wg, "接收者2") wg.Wait() } |
协程任务的取消
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package concurrency import ( "fmt" "testing" "time" ) func isCancelled(cancelChan chan struct{}) bool { select { case <-cancelChan: return true default: return false } } func TestCancel(t *testing.T) { cancelChan := make(chan struct{}, 0) for i := 0; i < 5; i++ { go func(i int, cancelCh chan struct{}) { //创建协程5个 for { if isCancelled(cancelCh) { //停止机制就是看cancelChan有没有数据传递进来,有就停止 break } time.Sleep(time.Millisecond * 5) fmt.Println(i, "任务开始") } fmt.Println(i, "for循环被取消") }(i, cancelChan) } /** * 直接关闭所有协程 */ close(cancelChan) /** * 往 cancelChan 传入数据取消一个协程 */ //cancelChan <- struct{}{} //cancelChan <- struct{}{} //cancelChan <- struct{}{} //cancelChan <- struct{}{} //cancelChan <- struct{}{} time.Sleep(time.Second * 1) //停1秒总进程 } |
协程任务关联取消
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package cancel import ( "context" "fmt" "testing" "time" ) func isCancelled(ctx context.Context) bool { select { case <-ctx.Done(): return true default: return false } } func TestCancel(t *testing.T) { //关联取消没有声明 chan ctx, cancel := context.WithCancel(context.Background()) for i := 0; i < 5; i++ { go func(i int, ctx context.Context) { for { if isCancelled(ctx) { break } fmt.Println(i, "任务开始") time.Sleep(time.Millisecond * 5) } fmt.Println(i, "for循环被取消") }(i, ctx) } cancel() time.Sleep(time.Second * 1) } |
只允许一次, 单一模式,懒加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package once_test import ( "fmt" "sync" "testing" "unsafe" ) /** * 声明一个结构 */ type Singleton struct { data string } var singleInstance *Singleton //声明变量的结构类型 var once sync.Once func GetSingletonObj() *Singleton { //只执行一次 once.Do(func() { fmt.Println("创建 Obj") singleInstance = new(Singleton) }) return singleInstance } func TestGetSingletonObj(t *testing.T) { var wg sync.WaitGroup //为了让进程等待协程 /** * 可以看见循环调用了多次, 内存地址还是一样的 */ for i := 0; i < 10; i++ { wg.Add(1) go func() { obj := GetSingletonObj() //创建一个安全单一的 fmt.Printf("%X\n", unsafe.Pointer(obj)) wg.Done() //通知结束 }() } wg.Wait() } |
多任务并发,一个任务完成其余停止
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package concurrency import ( "fmt" "runtime" "testing" "time" ) /** * 顶一个说话方法 */ func runTask(id int) string { time.Sleep(10 * time.Millisecond) return fmt.Sprintf("我会说话结果来自 %d", id) } /** * 并发执行10个说话方法 * 可以看出没有使用 make(chan string, numOfRunner) 的会有消息阻塞 * 所以可以看出写 "多任务并发一个任务完成就成功" 需要使用 make(chan string, numOfRunner) * 减少阻塞 */ func FirstResponse() string { numOfRunner := 10 //ch := make(chan string) ch := make(chan string, numOfRunner) for i := 0; i < numOfRunner; i++ { go func(i int) { ch <- runTask(i) }(i) } return <-ch } func TestFirstResponse(t *testing.T) { t.Log("之前协程数:", runtime.NumGoroutine()) t.Log(FirstResponse()) time.Sleep(time.Second * 1) t.Log("之后协程数:", runtime.NumGoroutine()) } |
所有协程任务完成程序结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package util_all_done import ( "fmt" "runtime" "testing" "time" ) func runTask(id int) string { time.Sleep(10 * time.Millisecond) return fmt.Sprintf("我说话了妈妈 %d", id) } func AllResponse() string { numOfRunner := 10 ch := make(chan string, numOfRunner) for i := 0; i < numOfRunner; i++ { go func(i int) { ret := runTask(i) ch <- ret }(i) } finalRet := "" for i := 0; i < numOfRunner; i++ { finalRet += <-ch + "\n" } return finalRet } func TestFirstResponse(t *testing.T) { t.Log("之前线程数:", runtime.NumGoroutine()) t.Log(AllResponse()) //这里输出我说了妈妈 time.Sleep(time.Second * 1) t.Log("之后线程数:", runtime.NumGoroutine()) } |