• Golang脱坑指南: goroutine(不断更新)


    源代码与测试代码 https://github.com/YJZhangChina/GNP/tree/master/basic 下 goroutine_traps.go 与 goroutine_traps_test.go

    1. 不安全的指针传递

    Goroutine的调度次序未知,如果执行多次有指针传递的函数,且函数内存在写操作,需要考虑脏读和原子性问题。定义了Message结构体存储当前值current,valueChange方法用于修改current为当前步骤数step,并用Message指导后续操作。多次运goroutine执行该方法,由于指针传递,Message实例仅有一份,goroutine无法保证函数流程的原子性,造成了写无效和脏读。适当增大循环次数size可更容易发现该问题。

    Testing UnsafePointerPassing in GoroutineTraps // 模拟结果可能不同
    After step 9 the value is 9.
    After step 0 the value is 0.
    After step 1 the value is 1.
    After step 2 the value is 2.
    After step 3 the value is 3.
    After step 4 the value is 4.
    After step 7 the value is 7.
    After step 8 the value is 8.
    After step 5 the value is 5.
    After step 6 the value is 5. // Error

    指针传递前对Message实例进行克隆,产生写时复制的效果,修改后的结果不受影响。

    Testing SafePointerPassing in GoroutineTraps // 模拟结果可能不同
    After step 0 the value is 0.
    After step 9 the value is 9.
    After step 5 the value is 5.
    After step 6 the value is 6.
    After step 7 the value is 7.
    After step 8 the value is 8.
    After step 2 the value is 2.
    After step 1 the value is 1.
    After step 3 the value is 3.
    After step 4 the value is 4.

    goroutine_traps.go

    package basic
    
    import (
    	"fmt"
    	"sync"
    )
    
    type Message struct {
    	current int
    }
    
    func valueChange(step int, message *Message, waiter *sync.WaitGroup) {
    	message.current = step
    	fmt.Printf("After step %d the value is %d.
    ", step, message.current)
    	waiter.Done()
    }
    

    goroutine_traps_test.go

    package basic
    
    import (
    	"fmt"
    	"sync"
    	"testing"
    )
    
    func TestUnsafePointerPassing(t *testing.T) {
    	fmt.Println("Testing UnsafePointerPassing in GoroutineTraps")
    	size := 10
    	var waiter sync.WaitGroup
    	waiter.Add(size)
    	message := &Message{current: 1}
    	for i := 0; i < size; i++ {
    		go valueChange(i+1, message, &waiter)
    	}
    	waiter.Wait()
    }
    
    func TestSafePointerPassing(t *testing.T) {
    	fmt.Println("Testing SafePointerPassing in GoroutineTraps")
    	size := 10
    	var waiter sync.WaitGroup
    	waiter.Add(size)
    	message := &Message{current: 1}
    	for i := 0; i < 10; i++ {
    		var clone = new(Message)
    		*clone = *message
    		go valueChange(i+1, clone, &waiter)
    	}
    	waiter.Wait()
    }
    
  • 相关阅读:
    CentOS 7中firewall防火墙详解和配置以及切换为iptables防火墙
    使用kubeadm安装Kubernetes v1.10
    Docker版本变化和新版安装
    Kubernetes实践--hello world 示例
    kubernetes常用命令
    区块链入门教程
    Json概述以及python对json的相关操作
    linux activiti5.22 流程图乱码
    Spring Cloud Gateway 实现Token校验
    oauth table
  • 原文地址:https://www.cnblogs.com/miluroe/p/10993210.html
Copyright © 2020-2023  润新知