go的并发初体验、加锁、异步

简介: go的并发初体验、加锁、异步

一、使用关键字go并发

package groutine_test
 
import (
  "fmt"
  "testing"
  "time"
)
 
func TestGroutine(t *testing.T) {
  for i := 0; i < 10; i++ {
    //启动协程
    go func(i int) {
      fmt.Println(i)
    }(i)
  }
  time.Sleep(time.Millisecond * 50)
}
=== RUN   TestGroutine
9
5
6
7
8
1
0
2
3
4
--- PASS: TestGroutine (0.05s)
PASS

二、并发锁

package share_mem
 
import (
  "sync"
  "testing"
  "time"
)
 
//协程不安全
func TestCounter(t *testing.T) {
  counter := 0
  for i := 0; i < 5000; i++ {
    //并发计数
    go func() {
      counter++
    }()
  }
  time.Sleep(time.Second * 1)
  t.Logf("counter=%d", counter)
}
//协程安全
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(time.Second * 1)
  t.Logf("counter=%d", counter)
}
 
//WaitGroup 所有组完成后,继续执行
func TestCounterWaitGroup(t *testing.T) {
  //获取锁
  var wg sync.WaitGroup
  var mut sync.Mutex
  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)
}

三、异步执行

package csp
 
import (
  "fmt"
  "testing"
  "time"
)
 
//串行
func service() string {
  time.Sleep(time.Millisecond * 50)
  return "Done"
}
 
//串行
func otherTask() {
  fmt.Println("working on somthing else")
  time.Sleep(time.Millisecond * 100)
  fmt.Println("Task is done.")
}
func TestService(t *testing.T) {
  fmt.Println(service())
  otherTask()
}
 
//异步 chan在go中是一个通道有可读可写的chan,也存在只读只写的chan 异步返回
func AsyncService() chan string {
  //创建接受通道
  retCh := make(chan string, 1)
  go func() {
    ret := service()
    fmt.Println("returned result.")
    //chan放数据
    retCh <- ret
    fmt.Println("service exited.")
  }()
  return retCh
}
func TestAsynService(t *testing.T) {
  retCh := AsyncService()
  otherTask()
  //chan取数据
  fmt.Println(<-retCh)
  //time.Sleep(time.Second * 1)
}

异步执行后,快乐0.06s

目录
相关文章
|
3天前
|
安全 Go
Go语言map并发安全,互斥锁和读写锁谁更优?
Go并发编程中,`sync.Mutex`提供独占访问,适合读写操作均衡或写操作频繁的场景;`sync.RWMutex`允许多个读取者并行,适用于读多写少的情况。明智选择锁可提升程序性能和稳定性。示例展示了如何在操作map时使用这两种锁。
6 0
|
3天前
|
安全 Go 开发者
Go语言map并发安全使用的正确姿势
在Go并发编程中,由于普通map不是线程安全的,多goroutine访问可能导致数据竞态。为保证安全,可使用`sync.Mutex`封装map或使用从Go 1.9开始提供的`sync.Map`。前者通过加锁手动同步,后者内置并发控制,适用于多goroutine共享。选择哪种取决于具体场景和性能需求。
6 0
|
3天前
|
存储 安全 Java
Go语言中的map为什么默认不是并发安全的?
Go语言的map默认不保证并发安全,以优化性能和简洁性。官方建议在需要时使用`sync.Mutex`保证安全。从Go 1.6起,并发读写map会导致程序崩溃,鼓励开发者显式处理并发问题。这样做的哲学是让代码更清晰,并避免不必要的性能开销。
4 0
|
25天前
|
监控 Go
go语言并发实战——日志收集系统(十一)基于etcd来监视配置文件的变化
go语言并发实战——日志收集系统(十一)基于etcd来监视配置文件的变化
|
26天前
|
监控 Go
go语言并发实战——日志收集系统(十) 重构tailfile模块实现同时监控多个日志文件
go语言并发实战——日志收集系统(十) 重构tailfile模块实现同时监控多个日志文件
|
5天前
|
JSON 测试技术 Go
零值在go语言和初始化数据
【7月更文挑战第10天】本文介绍在Go语言中如何初始化数据,未初始化的变量会有对应的零值:bool为`false`,int为`0`,byte和string为空,pointer、function、interface及channel为`nil`,slice和map也为`nil`。。本文档作为指南,帮助理解Go的数据结构和正确使用它们。
53 22
零值在go语言和初始化数据
|
7天前
|
安全 算法 程序员
在go语言中使用泛型和反射
【7月更文挑战第8天】本文介绍go支持泛型后,提升了代码复用,如操作切片、映射、通道的函数,以及自定义数据结构。 泛型适用于通用数据结构和函数,减少接口使用和类型断言。
68 1
在go语言中使用泛型和反射
|
9天前
|
缓存 编译器 Shell
回顾go语言基础中一些特别的概念
【7月更文挑战第6天】本文介绍Go语言基础涵盖包声明、导入、函数、变量、语句和表达式以及注释。零值可用类型如切片、互斥锁和缓冲,支持预分配容量以优化性能。
40 2
回顾go语言基础中一些特别的概念
|
13天前
|
存储 Go API
一个go语言编码的例子
【7月更文挑战第2天】本文介绍Go语言使用Unicode字符集和UTF-8编码。Go中,`unicode/utf8`包处理编码转换,如`EncodeRune`和`DecodeRune`。`golang.org/x/text`库支持更多编码转换,如GBK到UTF-8。编码规则覆盖7位至21位的不同长度码点。
115 1
一个go语言编码的例子
|
5天前
|
JSON Java Go
Go 语言性能优化技巧
在Go语言中优化性能涉及数字字符串转换(如用`strconv.Itoa()`代替`fmt.Sprintf()`)、避免不必要的字符串到字节切片转换、预分配切片容量、使用`strings.Builder`拼接、有效利用并发(`goroutine`和`sync.WaitGroup`)、减少内存分配、对象重用(`sync.Pool`)、无锁编程、I/O缓冲、正则预编译和选择高效的序列化方法。这些策略能显著提升代码执行效率和系统资源利用率。
41 13