Golang sync.WaitGroup源码详细分析

waitgroup与互斥锁底层 版本中引入了饥饿模式,当goroutine超过1ms没有获取锁,那么就将当前的互斥锁切换到饥饿模式,在该模式下,互斥锁会直接交给等待队列最前面的g,新的g在该状态下既不能获取锁,也不会进入自旋状态,只会在队列的末尾等待。锁的使用场景是解决多协程下数据竞态的问题,为了保证数据的安全,锁住一些共享资源。mutex的最开始实现只有正常模式,在正常模式下等待的线程按照先进先出的方式获取锁,但是新创建的goroutine会与刚被唤醒的goroutine竞争,导致刚被唤起的goroutine拿不到锁,从而长期被阻塞。 阅读详情

一、介绍

WaitGroup是多个goroutine之间协作的一种实现方式,主要功能就是阻塞等待一组goroutine执行完成。

 

常用的使用场景:主goroutine调用Add函数设置需要等待的goroutine的数量,当每个goroutine执行完成后调用Done函数(将counter减1),Wait函数用于阻塞等待直到该组中的所有goroutine都执行完成。

 

源码中主要设计到的三个概念:counter、waiter和semaphore

counter: 当前还未执行结束的goroutine计数器

waiter : 等待goroutine-group结束的goroutine数量,即有多少个等候者

semaphore: 信号量

信号量是Unix系统提供的一种保护共享资源的机制,用于防止多个线程同时访问某个资源。

可简单理解为信号量为一个数值:

当信号量>0时,表示资源可用,获取信号量时系统自动将信号量减1;

当信号量=0时,表示资源暂不可用,获取信号量时,当前线程会进入睡眠,当信号量为正时被唤醒。

 

二、源码分析

Golang源码版本 :1.10.3

1.结构体

  type WaitGroup struct {
	noCopy noCopy  //该WaitGroup对象不允许拷贝使用,只能用指针传递

	// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
	// 64-bit atomic operations require 64-bit alignment, but 32-bit
	// compilers do not ensure it. So we allocate 12 bytes and then use
	// the aligned 8 bytes in them as state.
	//用于存储计数器(counter)和waiter的值
	// 只需要64位,即8个字节,其中高32位是counter值,低32位值是waiter值
	// 不直接使用uint64,是因为uint64的原子操作需要64位系统,而32位系统下,可能会出现崩溃
	// 所以这里用byte数组来实现,32位系统下4字节对齐,64位系统下8字节对齐,所以申请12个字节,其中必定有8个字节是符合8字节对齐的,下面的state()函数中有进行判断
	state1 [12]byte
	sema   uint32  //信号量
}

    从结构体中我们看到

     state1是一个12位长度的byte数组,用于存储counter和waiter的值

     sema就是传说中的信号量

2.state函数

state是一个内部函数,用于获取counter和 waiter的值

//获取counter  、 waiter的值  (counter是uint64的高32位,waiter是uint64的低32位)
func (wg *WaitGroup) state() *uint64 {
	// 根据state1的起始地址分析,若是8字节对齐的,则直接用前8个字节作为*uint64类型
	// 若不是,说明是4字节对齐,则后移4个字节后,这样必为8字节对齐,然后取后面8个字节作为*uint64类型
	if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
		return (*uint64)(unsafe.Pointer(&wg.state1))
	} else {
		return (*uint64)(unsafe.Pointer(&wg.state1[4]))
	}
}

3.Add方法

//用于增加或减少计数器(counter)的值
//如果计数器为0,则释放调用Wait方法时的阻塞,如果计数器为负,则panic
//Add()方法应该在Wait()方法调用之前
func (wg *WaitGroup) Add(delta int) {
	//获取当前counter和 waiter的值
	statep := wg.state()
	if race.Enabled {
		_ = *statep // trigger nil deref early
		if delta < 0 {
			// Synchronize decrements with Wait.
			race.ReleaseMerge(unsafe.Pointer(wg))
		}
		race.Disable()
		defer race.Enable()
	}

	//将delta的值添加到counter上
	state := atomic.AddUint64(statep, uint64(delta)<<32)
	v := int32(state >> 32)  //counter值
	w := uint32(state)  //waiter值
	if race.Enabled && delta > 0 && v == int32(delta) {
		// The first increment must be synchronized with Wait.
		// Need to model this as a read, because there can be
		// several concurrent wg.counter transitions from 0.
		race.Read(unsafe.Pointer(&wg.sema))
	}

	//counter为负数,则触发panic
	if v < 0 {
		panic("sync: negative WaitGroup counter")
	}

	// waiter值不为0,累加后的counter值和delta相等,说明Wait()方法没有在Add()方法之后调用,触发panic,因为正确的做法是先Add()后Wait()
	if w != 0 && delta > 0 && v == int32(delta) {
		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
	}

	//Add()添加正常返回
	//1.counter > 0,说明还不需要释放信号量,可以直接返回
	//2. waiter  = 0 ,说明没有等待的goroutine,也不需要释放信号量,可以直接返回
	if v > 0 || w == 0 {
		return
	}
	// This goroutine has set counter to 0 when waiters > 0.
	// Now there can't be concurrent mutations of state:
	// - Adds must not happen concurrently with Wait,
	// - Wait does not increment waiters if it sees counter == 0.
	// Still do a cheap sanity check to detect WaitGroup misuse.
	//下面是 counter == 0 并且 waiter > 0的情况
	//现在若原state和新的state不等,则有以下两种可能
	//1. Add 和 Wait方法同时调用
	//2. counter已经为0,但waiter值有增加,这种情况永远不会触发信号量了
	// 以上两种情况都是错误的,所以触发异常
	//注:state := atomic.AddUint64(statep, uint64(delta)<<32)  这一步调用之后,state和*statep的值应该是相等的,除非有以上两种情况发生
	if *statep != state {
		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
	}
	// Reset waiters count to 0.
	//将waiter 和 counter都置为0
	*statep = 0
	//原子递减信号量,并通知等待的goroutine
	for ; w != 0; w-- {
		runtime_Semrelease(&wg.sema, false)
	}
}

  4.Done方法

// Done decrements the WaitGroup counter by one.
//将计数器(counter)的值减1
func (wg *WaitGroup) Done() {
	wg.Add(-1)
}

5.Wait方法

// Wait blocks until the WaitGroup counter is zero.
//调用Wait方法会阻塞当前调用的goroutine直到 counter的值为0
//也会增加waiter的值
func (wg *WaitGroup) Wait() {
	//获取当前counter和 waiter的值
	statep := wg.state()
	if race.Enabled {
		_ = *statep // trigger nil deref early
		race.Disable()
	}
	//一直等待,直到无需等待或信号量触发,才返回
	for {
		state := atomic.LoadUint64(statep)
		v := int32(state >> 32)  //counter值
		w := uint32(state)  //waiter值
		//如果counter值为0,则说明所有goroutine都退出了,无需等待,直接退出
		if v == 0 {
			// Counter is 0, no need to wait.
			if race.Enabled {
				race.Enable()
				race.Acquire(unsafe.Pointer(wg))
			}
			return
		}

		// Increment waiters count.
		//原子增加waiter的值,CAS方法,外面for循环会一直尝试,保证多个goroutine同时调用Wait()也能正常累加waiter
		if atomic.CompareAndSwapUint64(statep, state, state+1) {
			if race.Enabled && w == 0 {
				// Wait must be synchronized with the first Add.
				// Need to model this is as a write to race with the read in Add.
				// As a consequence, can do the write only for the first waiter,
				// otherwise concurrent Waits will race with each other.
				race.Write(unsafe.Pointer(&wg.sema))
			}
			//一直等待信号量sema,直到信号量触发,
			runtime_Semacquire(&wg.sema)
			//从上面的Add()方法看到,触发信号量之前会将seatep置为0(即counter和waiter都置为0),所以此时应该也为0
			//如果不为0,说明WaitGroup此时又执行了Add()或者Wait()操作,所以会触发panic
			if *statep != 0 {
				panic("sync: WaitGroup is reused before previous Wait has returned")
			}
			if race.Enabled {
				race.Enable()
				race.Acquire(unsafe.Pointer(wg))
			}
			return
		}
	}
}

 

三、注意点

1.Add()必须在Wait()前调用

2.Add()设置的值必须与实际等待的goroutine个数一致,如果设置的值大于实际的goroutine数量,可能会一直阻塞。如果小于会触发panic

3. WaitGroup不可拷贝,可以通过指针传递,否则很容易造成BUG

 

以下为值拷贝引起的Bug示例

demo1:因为值拷贝引起的死锁

func main() {
	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0 ; i < 5 ; i++ {
	 	test(wg)
	}
	wg.Wait()
}

func test(wg sync.WaitGroup) {
	go func() {
		fmt.Println("hello")
		wg.Done()
	}()
}

 

demo2:因为值拷贝引起的不会阻塞等待现象

func main() {
	var wg sync.WaitGroup
	for i := 0 ; i < 5 ; i++ {
	 	test(wg)
	}
	wg.Wait()
}

func test(wg sync.WaitGroup) {
	go func() {
		wg.Add(1)
		fmt.Println("hello")
		time.Sleep(time.Second*5)
		wg.Done()
	}()
}

 

demo3:因为值拷贝引发的panic

type person struct {
	wg sync.WaitGroup
}

func (t *person) say()  {
	go func() {
		fmt.Println("say Hello!")
		time.Sleep(time.Second*5)
		t.wg.Done()
	}()
}


func main() {
	var wg sync.WaitGroup
	t := person{wg:wg}
	wg.Add(5)
	for  i := 0 ; i< 5 ;i++ {
		t.say()
	}
	wg.Wait()
}

 

感谢:https://blog.youkuaiyun.com/yzf279533105/article/details/97302666

Go语言中的sync.WaitGroup详解 是 Go 标准库sync包中的一个类型,主要用于同步多个协程的执行。它的核心作用是允许主程序或其他协程等待一组协程完成任务后再继续执行。1. 结构noCopy noCopy // 防止被复制state1 atomic.Uint64 // 用于原子操作的状态标志sema uint32 // 用于阻塞和唤醒WaitGroup内部通过原子操作(atomic)和信号量(sema)实现协程的同步。2. 核心方法增加或减少等待的任务数量(计数器)。delta > 0:增加任务数。delta < 0。 阅读详情

相关推荐

深度解析sync WaitGroup源码及其实现原理

目录 WaitGroup介绍 WaitGroup的实现 Add Done Wait WaitGroup介绍 waitGroup ,也是在go语言并发中比较常用的语法,所以在这里我们一起剖析 waitGroup 的使用方式及其源码解读。 WaitGroup 也是sync 包下一份子,用来解决任务编排的一个并发原语。它主要解决了并发-等待问题:比如现在有三个goroutine,分别为goroutineA,goroutineB,goroutineC,而goroutineA需要等待goroutineB和.

qq_41066066的博客 1485

简单介绍Go sync WaitGroup使用深入理解

只要 WaitGroup 的计值恢复到零值的状态,那么它就可以被看作是新创建的 WaitGroup,被重复使用,而不能在前一组没使用完的情况下又使用。而用WaitGroup时,协程A只用阻塞,直到其他协程执行完毕后,再通知协程A,其他语言也提供了类似的工具,例如Java的CountDownLatch。因此使用 WaitGroup 的正确姿势是,预先确定好 WaitGroup 的计数值,然后调用相同次数的 Done 完成相应的任务。// 如果加完后v大于0,或者加完后v等于0,但没有等待者,直接返回。

Free雅轩的博客 801

SQL注入:联合查询的三个绕过技巧

在SQL注入中,可以利用科学计数法来绕过对输入的限制。例如,可以使用科学计数法来绕过对字符串长度的限制,通过将字符串拆分成多个部分并使用科学计数法来表示。此外,还可以利用数据库的特定特性或语法来替代原始的查询语句,从而执行联合查询或其他恶意操作。另外,还可以尝试利用无列名注入的技巧,通过在原始查询中使用通配符或其他方式来绕过对列名的限制,从而执行恶意操作。

qq_68163788的博客 3795

panic: sync: negative WaitGroup counter

问题 先看报错信息 Table: 0 grass: 0 match: 0 Apple smokes a cigarette Table chooses paper: Sandy Table: 0 grass: 1 match: 1 Table: 0 grass: 1 match: 0 Table: 0 grass: 0 match: 0 Sandy smokes a cigarette panic: sync: negative WaitGroup counter goroutine 6 [running

pardon110的博客 4929

PINN——加入物理约束的神经网络

【摘要】 基于物理信息的神经网络(Physics-informed Neural Network, 简称PINN),是一类用于解决有监督学习任务的神经网络,它不仅能够像传统神经网络一样学习到训练数据样本的分布规律,而且能够学习到数学方程描述的物理定律。与纯数据驱动的神经网络学习相比,PINN在训练过程中施加了物理信息约束,因而能用更少的数据样本学习到更具泛化能力的模型。本文主要解析这种神经网络以...

qq_39444290的博客 4585

SGO基线解算软件(南方测绘UI设计最美观的一款新版)

不多说,先放地址: 下载地址:https://www.southgnss.com/download_view.asp?did=361 SGO是南方测绘集团广州南方卫星导航仪器有限公司自主研发新一代南方地理数据处理平台软件,对南方特有数据格式文件(STH格式文件)、标准数据格式文件(RINEX格式文件)进行静态数据处理、动态数据后处理和进行RTK结果检验,新增加了北斗数据处理和摄影测量模块,并围绕南方的不同类型测量产品集成多款测绘领域所需的小工具,实现测绘内业数据处理一体化。 相关概念 G..

heirenqiaoke的博客 1万+

Golang sync.WaitGroup 快速上手

sync.WaitGroup 用于阻塞等待一组 Go 程的结束。主 Go 程调用 Add() 来设置等待的 Go 程数,然后该组中的每个 Go 程都需要在运行结束时调用 Done(), 递减 WaitGroup 的 Go 程计数器 counter。当 counter 变为 0 时,主 Go 程被唤醒继续执行。// 设置需要等待的 Go 程数量。// Go 程计数器减 1。// 阻塞等待所有 Go 程结束(等待 Go 程计数器变为 0)。

Doublelv 的博客专栏。 5850

基于YOLOv8的水果新鲜程度检测系统设计与实现

数据采集与预处理模块:负责收集水果图像数据并进行标注和增强深度学习模型:基于YOLOv8的目标检测模型新鲜度评估模块:根据检测结果评估水果新鲜程度用户界面:提供友好的交互界面系统集成:将各模块整合为完整系统水果新鲜程度检测需要包含多种水果在不同新鲜度状态下的图像数据集。:包含5种常见水果(苹果、香蕉、橙子、葡萄、草莓)在不同新鲜度下的图像包含约8,000张图像,分为新鲜和腐烂两类AgriVision:大型农业图像数据集,包含水果检测和分类任务Fruit-360:包含120种水果的高质量图像。

YOLO 445

谈谈Golang的同步等待组

作者:ReganYue 来源:恒生LIGHT云社区 大家好,这里是努力变得优秀的R君,这次我们继续来进行Golang系列《让我们一起Golang》,区块链系列内容明年会继续更新,共识算法已经基本完毕,如果不出意外,元旦那个星期就是介绍如何构建公链项目了,本次我们来了解Golang的同步等待组,这也是一个比较容易理解的知识点,我们来看一看吧! 我们现在开十条子协程,然后当十条子协程全部结束后,主协程立马结束。动动你的小脑袋,想一想应该怎么做?如果是一条子协程的话就很容易实现,当这条子协程结束时让主协程结束.

weixin_44433834的博客 735

1. 在 SAP ABAP 事物码 SEGW 里创建 SAP OData 项目

本文介绍如何在 SAP ABAP 事物码 SEGW 里创建 SEGW 项目,使用工具生成 Runtime 运行时需要的资源。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5446

(王道计算机组成原理笔记)第一章计算机系统概述-第二节:计算机系统层次结构 1(计算机系统组成、计算机硬件)

文章目录一:冯诺依曼体系结构(1)存储程序计算机(2)层次结构二:计算机硬件概述(1)存储器A:存储元、存储单元、存储体、存储字和存储字长B:MAR 一:冯诺依曼体系结构 在冯诺依曼体系结构中,计算机的硬件主要有**存储器,运算器,控制器,输入和输出设备(也叫做I/O设备)**组成。 (1)存储程序计算机 冯诺依曼体系结构也叫做存储程序计算机,计算器和计算机的唯一区别就是计算器是不能编程的,只能做电路板中设定好的固定的运算。 这也就意味着计算器本质就是一个不能编程的计算机,其在硬件层面已经将逻辑写死,如果

快乐江湖的博客 1万+

Golang WaitGroup源码分析

Golang WaitGroup源码分析

cyxr001的博客 260

[QMT量化交易小白入门]-四十四、年化收益48%的策略要兼容回测和实盘,将实盘改为定时任务的方式

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 1376

golang waitgroup

WaitGroup可以用于一个 goroutine 等待多个 goroutine 干活完成,也可以多个 goroutine 等待一个 goroutine 干活完成,是一个多对多的关系多个等待一个的典型案例是,这个在后面将微服务可用性的时候还会再讲到,感兴趣可以看看源码Add(n>0)方法应该在启动 goroutine 之前调用,然后在 goroution 内部调用Done方法WaitGroup必须在Wait方法返回之后才能再次使用Done只是Add。

StackFlow的博客 3万+

【Windows Server 2019】邮件服务器配置与管理——安装及配置Winmail服务器(上)

博文介绍了如何安装邮件服务器 Winmail,如何配置Winmail,包括运行服务器,Winmail管理工具介绍和域名配置。

VMware, Windows, Linux, Cisco, Container, Kubernetes, Kali 2万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

go 源码解读 - sync.WaitGroup

在 Go 语言中,sync.WaitGroup 是一个并发编程的同步工具,用于等待一组 Goroutine 执行完毕。当需要等待多个 Goroutine 完成任务后才能执行下一步操作时,我们可以使用 sync.WaitGroup 实现协程间的同步。它提供了三个方法,分别用于计数、计数减一和等待协程执行完毕。具体来说:Add(delta int) 方法可以用于增加 WaitGroup 的计数器。每次调用 Add(),计数器就会增加 delta。如果delta 为负数,则会减少计数器。

qq_40484416的博客 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【源码解剖】Go任务编排助手sync.WaitGroup

golang中,WaitGroup的使用,基本使用方式,源码解读,注意事项

HC3244535的博客 1392

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Go sync.WaitGroup的学习

sync代码包的WaitGroup类型和Once类型都是非常易用的同步工具。它们都是开箱即用和并发安全的。利用WaitGroup值,我们可以很方便地实现一对多的 goroutine 协作流程,即:一个分发子任务的 goroutine,和多个执行子任务的 goroutine,共同来完成一个较大的任务。在使用WaitGroup值的时候,我们一定要注意,千万不要让其中的计数器的值小于0,否则就会引发 panic。另外,

天天新知 1403

Go sync.WaitGroup

1 前言 WaitGroup是Golang应用开发过程中经常使用的并发控制技术。 WaitGroup,可理解为Wait-Goroutine-Group,即等待一组goroutine结束。比如某个goroutine需要等待其他几个goroutine全部完成,那么使用WaitGroup可以轻松实现。 以下是1个goroutine等待另外2个goroutine结束的例子: package main import ( "fmt" "sync" ) func main() { var

weixin_43452467的博客 1068

golang waitgroup 及 sync.Once 示例

下面代码修改自golang示例源码 package main import ( "fmt" "sync" "net/http" "io/ioutil" "log" ) func GetDemo(addr string) { res, err := http.Get(addr) if err != nil { log.Fatal(err) } robots, err :=

冰焰· 2920

Golang Sync.WaitGroup 使用及原理

Golang Sync.WaitGroup 使用及原理 使用 func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println("Hello WaitGroup!") }() } wg.Wait() } 实现 首先看 waitgroup 到底是什么数据结构 type WaitGroup struct { noC

weixin_44046117的博客 775

手摸手Go 也谈sync.WaitGroup

最近因为工作上的事情更新会相对有点儿慢,这周末又加了天班。然后昨天好好休息了下,顺便翻了下《云雀叫了一整天》,看到一首小诗觉得不错分享给大家。从前慢木心记得早先少年时大家诚诚恳恳说一句是一...

sydhappy的专栏 625

go sync.WaitGroup源码分析

go版本 :1.10.3 原理实现:信号量 信号量是Unix系统提供的一种保护共享资源的机制,用于防止多个线程同时访问某个资源。 可简单理解为信号量为一个数值: 当信号量>0时,表示资源可用,获取信号量时系统自动将信号量减1; 当信号量==0时,表示资源暂不可用,获取信号量时,当前线程会进入睡眠,当信号量为正时被唤醒 WaitGroup的定义 type WaitGr...

papaya的博客 809

【Golang】——由浅入深分析并发利器sync.WaitGroup

一、前言 官方文档对sync.WatiGroup的描述是:一个waitGroup对象可以等待一组协程结束,也就等待一组goroutine返回。有了sync.Waitgroup我们可以将原本顺序执行的代码在多个Goroutine中并发执行,加快程序处理的速度。我们先来感受一下官方给出的样例:(官方给出的样例干的事情其实是访问三个网站,访问完成打印出来) package main import ( "fmt" "sync" "net/http" ) func mai...

汤庆 1063

「Golang」sync.WaitGroup源码讲解

sync.WaitGroup介绍 当我们在开发过程中,经常需要在开启多个goroutine后,等待全部的goroutine执行完毕后才进行下一步的业务逻辑执行。此时我们可能会采用轮询的方式去定时侦测已经开启的多个goroutine的业务是否执行完毕,但是这样性能很低,并且持续占用cpu时间片很消耗cpu的资源,此时我们就该使用sync.WaitGroup来完成此次操作。举个????,下列代码是开了10个goroutine后等待其各睡眠5秒之后进行后续操作的sync.WaitGroup方法实现。 func m

_Echo_ 466

golang sync.WaitGroup

go语言刚入门碰到第一个程序人懵了 package main import ( "fmt" "sync" ) var wg sync.WaitGroup func printer(ch chan int) { for i := range ch { fmt.Printf("Received %d ", i) } wg.Done() } // main is the entry point for the program. func main() { c := make(chan

weixin_44864571的博客 440
上一篇: Kafka Client源码中的NIO使用
下一篇: git提示error setting certificate verify locations错误解决
思维的深度
博客等级 码龄11年 2万+粉丝 391原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值