《快学 Go 语言》第 13 课 —— 并发与安全

go中数组、切片、map是否线程(并发)安全? 李某人带你了解go中数组、切片、map的线程安全(面试版) 阅读详情

上一节我们提到并发编程不同的协程共享数据的方式除了通道之外还有就是共享变量。虽然 Go 语言官方推荐使用通道的方式来共享数据,但是通过变量来共享才是基础,因为通道在底层也是通过共享变量的方式来实现的。通道的内部数据结构包含一个数组,对通道的读写就是对内部数组的读写。

在并发环境下共享读写变量必须要使用锁来控制数据结构的安全,Go 语言内置了 sync 包,里面包含了我们平时需要经常使用的互斥锁对象 sync.Mutex。Go 语言内置的字典不是线程安全的,所以下面我们尝试使用互斥锁对象来保护字典,让它变成线程安全的字典。

线程不安全的字典

Go 语言内置了数据结构「竞态检查」工具来帮我们检查程序中是否存在线程不安全的代码。当我们在运行代码时,打开 -run 开关,程序就会在内置的通用数据结构中进行埋点检查。竞态检查工具在 Go 1.1 版本中引入,该功能帮助 Go 语言「元团队」找出了 Go 语言标准库中几十个存在线程安全隐患的 bug,这是一个非常了不起的功能。同时这也说明了即使是猿界的神仙,写出来的代码也避免不了有 bug。下面我们来尝试一下

package main

import "fmt"

func write(d map[string]int) {
    d["fruit"] = 2
}

func read(d map[string]int) {
    fmt.Println(d["fruit"])
}

func main() {
    d := map[string]int{}
    go read(d)
    write(d)
}

$ go run -race main.go
==================
WARNING: DATA RACE
Read at 0x00c420090180 by goroutine 6:
  runtime.mapaccess1_faststr()     
  /usr/local/Cellar/go/1.10.3/libexec/src/runtime/hashmap_fast.go:172 +0x0
  main.read()
      ~/go/src/github.com/pyloque/practice/main.go:10 +0x5d

Previous write at 0x00c420090180 by main goroutine:
  runtime.mapassign_faststr()
/usr/local/Cellar/go/1.10.3/libexec/src/runtime/hashmap_fast.go:694 +0x0
  main.main()
      ~/go/src/github.com/pyloque/practice/main.go:6 +0x88

Goroutine 6 (running) created at:
  main.main()
      ~/go/src/github.com/pyloque/practice/main.go:15 +0x59
==================
==================
WARNING: DATA RACE
Read at 0x00c4200927d8 by goroutine 6:
  main.read()
      ~/go/src/github.com/pyloque/practice/main.go:10 +0x70

Previous write at 0x00c4200927d8 by main goroutine:
  main.main()
      ~/go/src/github.com/pyloque/practice/main.go:6 +0x9b

Goroutine 6 (running) created at:
  main.main()
      ~/go/src/github.com/pyloque/practice/main.go:15 +0x59
==================
2
Found 2 data race(s)

线程安全的字典

让字典变的线程安全,就需要对字典的所有读写操作都使用互斥锁保护起来。

package main

import "fmt"
import "sync"

type SafeDict struct {
    data  map[string]int
    mutex *sync.Mutex
}

func NewSafeDict(data map[string]int) *SafeDict {
    return &SafeDict{
        data:  data,
        mutex: &sync.Mutex{},
    }
}

func (d *SafeDict) Len() int {
    d.mutex.Lock()
    defer d.mutex.Unlock()
    return len(d.data)
}

func (d *SafeDict) Put(key string, value int) (int, bool) {
    d.mutex.Lock()
    defer d.mutex.Unlock()
    old_value, ok := d.data[key]
    d.data[key] = value
    return old_value, ok
}

func (d *SafeDict) Get(key string) (int, bool) {
    d.mutex.Lock()
    defer d.mutex.Unlock()
    old_value, ok := d.data[key]
    return old_value, ok
}

func (d *SafeDict) Delete(key string) (int, bool) {
    d.mutex.Lock()
    defer d.mutex.Unlock()
    old_value, ok := d.data[key]
    if ok {
        delete(d.data, key)
    }
    return old_value, ok
}

func write(d *SafeDict) {
    d.Put("banana", 5)
}

func read(d *SafeDict) {
    fmt.Println(d.Get("banana"))
}

func main() {
    d := NewSafeDict(map[string]int{
        "apple": 2,
        "pear":  3,
    })
    go read(d)
    write(d)
}

在上面的代码中我们再次看到了 defer 语句的应用场景 —— 释放锁。defer 语句总是要推迟到函数尾部运行,所以如果函数逻辑运行时间比较长,这会导致锁持有的时间较长,这时使用 defer 语句来释放锁未必是一个好注意。

避免锁复制

上面的代码中还有一个需要特别注意的地方是 sync.Mutex 是一个结构体对象,这个对象在使用的过程中要避免被复制 —— 浅拷贝。复制将会导致锁被「分裂」了,也就起不到保护的作用。所以在平时的使用中要尽量使用它的指针类型。读者可以尝试将上面的类型换成非指针类型,然后运行一下竞态检查工具,会看到警告信息再次布满整个屏幕。锁复制存在于结构体变量的赋值、函数参数传递、方法参数传递中,都需要注意。

使用匿名锁字段

在结构体章节,我们知道外部结构体可以自动继承匿名内部结构体的所有方法。如果将上面的 SafeDict 结构体进行改造,将锁字段匿名,就可以稍微简化一下代码。

package main

import "fmt"
import "sync"

type SafeDict struct {
    data  map[string]int
    *sync.Mutex
}

func NewSafeDict(data map[string]int) *SafeDict {
    return &SafeDict{data, &sync.Mutex{}}
}

func (d *SafeDict) Len() int {
    d.Lock()
    defer d.Unlock()
    return len(d.data)
}

func (d *SafeDict) Put(key string, value int) (int, bool) {
    d.Lock()
    defer d.Unlock()
    old_value, ok := d.data[key]
    d.data[key] = value
    return old_value, ok
}

func (d *SafeDict) Get(key string) (int, bool) {
    d.Lock()
    defer d.Unlock()
    old_value, ok := d.data[key]
    return old_value, ok
}

func (d *SafeDict) Delete(key string) (int, bool) {
    d.Lock()
    defer d.Unlock()
    old_value, ok := d.data[key]
    if ok {
        delete(d.data, key)
    }
    return old_value, ok
}

func write(d *SafeDict) {
    d.Put("banana", 5)
}

func read(d *SafeDict) {
    fmt.Println(d.Get("banana"))
}

func main() {
    d := NewSafeDict(map[string]int{
        "apple": 2,
        "pear":  3,
    })
    go read(d)
    write(d)
}

使用读写锁

日常应用中,大多数并发数据结构都是读多写少的,对于读多写少的场合,可以将互斥锁换成读写锁,可以有效提升性能。sync 包也提供了读写锁对象 RWMutex,不同于互斥锁只有两个常用方法 Lock() 和 Unlock(),读写锁提供了四个常用方法,分别是写加锁 Lock()、写释放锁 Unlock()、读加锁 RLock() 和读释放锁 RUnlock()。写锁是拍他锁,加写锁时会阻塞其它协程再加读锁和写锁,读锁是共享锁,加读锁还可以允许其它协程再加读锁,但是会阻塞加写锁。

读写锁在写并发高的情况下性能退化为普通的互斥锁

下面我们将上面代码中 SafeDict 的互斥锁改造成读写锁。

package main

import "fmt"
import "sync"

type SafeDict struct {
    data  map[string]int
    *sync.RWMutex
}

func NewSafeDict(data map[string]int) *SafeDict {
    return &SafeDict{data, &sync.RWMutex{}}
}

func (d *SafeDict) Len() int {
    d.RLock()
    defer d.RUnlock()
    return len(d.data)
}

func (d *SafeDict) Put(key string, value int) (int, bool) {
    d.Lock()
    defer d.Unlock()
    old_value, ok := d.data[key]
    d.data[key] = value
    return old_value, ok
}

func (d *SafeDict) Get(key string) (int, bool) {
    d.RLock()
    defer d.RUnlock()
    old_value, ok := d.data[key]
    return old_value, ok
}

func (d *SafeDict) Delete(key string) (int, bool) {
    d.Lock()
    defer d.Unlock()
    old_value, ok := d.data[key]
    if ok {
        delete(d.data, key)
    }
    return old_value, ok
}

func write(d *SafeDict) {
    d.Put("banana", 5)
}

func read(d *SafeDict) {
    fmt.Println(d.Get("banana"))
}

func main() {
    d := NewSafeDict(map[string]int{
        "apple": 2,
        "pear":  3,
    })
    go read(d)
    write(d)
}

640?wx_fmt=png

扫一扫二维码,订阅《快学 Go 语言》更多内容

深入理解 GO 语言并发 介绍了并发和并行的概念,以及编程错误可能造成的一些问题。Go 支持并发,并且可帮助处理很多后台工作。另外介绍了如何通过创建和使用协程将并发应用于 Go 应用程序,还使用通道在协程之间进行数据传递。 阅读详情

相关推荐

面试制胜秘籍:深入解析Go语言的并发之谜与面试难题

这些面试题覆盖了Go语言的核心概念,理解这些概念对于编写高效、可靠的Go代码至关重要。在准备面试时,确保你不仅理解这些概念,还能够编写和解释相关的代码示例。Go语言(Golang)的面试题通常覆盖了语言的基础知识、并发编程、内存管理、标准库的使用等多个方面。

weixin_39801169的博客 1153

aslist,gloang线程安全可排序的list

aslist aslist(A Sorted List)是golang语言实现的线程安全可排序的list。便捷的调用方式,使开发者快速入门使用。 前言 近来有喷子喷我,说golang有排序框架何苦要自己造轮子。我只想说中国的拿来主义思想就是导致今天中国为何终始没有自主研发的操作系统,没有自己的芯片。你跟我说这句话就像问"已经有了Java为什么还要学Golang、为什么男人有了老婆还想有小三...

郭钟的专栏 1730

AIR780E二次开发点灯(LuatOS)

Air780E的LuatOS点灯教程,二次开发教程,可用于所有ec618平台,无需SDK

rootuseres的博客 1万+

Go语言数据类型的并发安全

go语言数据类型的并发安全

huan 1134

希捷硬盘卡死修复实战:U盘启动盘制作与低格清零全流程

机械硬盘使用多年后常出现卡顿、假死、坏道等问题,很多用户在网上搜索“希捷硬盘低格工具”或“U盘硬盘复活器”,却发现要么工具不明,要么操作不当造成二次损伤。其实所谓修复工具,本质是U盘启动环境配合硬盘检测与清零软件,低格并非修复物理坏道,而是通过全盘写零触发主控重映射,隔离不稳定扇区。懂原理后,用官方SeaTools、Ventoy/U盘启动盘、Victoria或Linux dd等组合工具,即可对可抢救的硬盘做清零修复。这一技术适用于逻辑坏道、SMART警告、扇区不稳定等场景,但需先备份数据并判断盘体是否有异响

weixin_30431445的博客 219

Android——Handler详解

1. 简介 Handler是一套 Android 消息传递机制 可以说只要有异步线程与主线程通信的地方就一定会有 Handler。 在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理 使用Handler消息传递机制主要是为了多个线程并发更新UI的同时,保证线程安全 2. 相关概念解释 Handler、Message、Message Queue、Looper Android消息机制: 以Handler的sendMes

Yawn 7万+

Go面试问题(牛客整理版)

sync.Map通过分段锁、细粒度的锁控制、只读视图遍历等机制,实现了高效的并发读写操作,特别适合在高并发场景下替代标准的map来保证线程安全,同时减少锁的竞争,提升性能。不过,需要注意的是,由于其内部实现较为复杂,相比于普通的map,在单线程或低并发场景下,它的性能可能会稍逊一筹。gRPC在实现过程中,涉及多个层次的技术栈和组件,这些层次共同构成了其高效、可靠的通信机制。接口定义层(IDL - Interface Definition Language)

不思考会变草履虫哦 1074

使用 MATLAB/Simulink + Deep Learning Toolbox,构建一个基于LSTM的电网负荷预测模

本文介绍了一个基于Simulink和深度学习的智能电网负荷预测与调度建模方法。通过LSTM神经网络构建负荷预测模型,将历史负荷、天气、日期等特征作为输入,预测未来24小时负荷。然后将训练好的模型集成到Simulink仿真系统中,结合发电单元模型和经济调度逻辑,实现预测驱动的电力调度优化。实验结果表明,该方法预测误差在2.5%-4.0%之间,相比传统调度方式可降低15%-25%的运行成本。文章详细展示了从数据准备、特征工程、模型训练到系统集成的完整流程,为智能电网中AI技术的应用提供了实用参考。

amy_mhd的博客 172

大家一起学Golang——Go语言简介与安装

一起学习Golang ——Go语言简介与安装 go语言简介 Go语言是有google公司推出的一门编程语言,是开源,静态编程语言,语法简洁,天生支持并发。 2007年由Robert Griesemer, Rob Pike, Ken Thompson主持开发,又来加入了Ian Lance Taylor, Russ Cox等⼈,在2009年11⽉开源。 go语言特点 简洁 快速 安全 并行 开源 内...

c0586的专栏 925

【C语言趣味教程】(0) 专栏介绍

这是一套C 语言趣味教学专栏,目前正在火热连载中,欢迎猛戳订阅!本专栏保证篇篇精品,继续保持本人一贯的幽默式写作风格,当然,在有趣的同时也同样会保证文章的质量,旨在能够产出"有趣的干货" !本系列教程不管是零基础还是有基础的读者都可以阅读,可以先看看目录!标题前带星号 (*) 的部分不建议初学者阅读,因为内容难免会超出当前章节的知识点,面向的是对 C 语言有一定基础或已经学过

有道无术, 术尚可求。有术无道, 止于术。 2万+

C语言从句柄到对象 (一) —— 全局变量的噩梦与“多实例”的救赎

本文探讨了嵌入式开发中句柄(Handle)的概念与应用。通过电机控制案例,分析了传统单例模式在扩展性上的局限,并展示了如何通过句柄实现代码复用:将电机状态封装为结构体,通过指针(句柄)传递实例数据,使同一套逻辑可操作多个实例。文章比较了单例模式与句柄模式的适用场景,建议底层驱动库默认采用句柄模式以提高扩展性。最后指出当前实现仍存在数据暴露风险,预告下期将介绍不透明指针技术实现更安全的封装。全文揭示了句柄作为C语言实现模块化和面向对象设计的关键作用。

一路往蓝-Anbo 的博客 1341

GoLang之切片并发安全问题

GoLang之切片并发安全问题

weixin_52690231的博客 2740

AI上推荐 之 AutoInt模型(Transformer开始玩特征交互)

1. 写在前面 这段时间做优化模型的事情,正好和特征交互有关系,这个也是推荐系统里面一直探索的一个方向,从浅层模型的FM, FFM, HOFM, FwFM到深层模型的DNN, PNN, NFM, AFM, DeepFM, DCN, xDeepFM, FiBiNet等,而这次正好借着这次机会, 多看一些有关于特征交叉方向的模型paper, 把一些新的模型或者较为前沿的思想融入进来。 上一篇的FiBinet模型就是在特征交互上一个非常有意思的探索, 通过SENET动态选择有用的交互特征, 然后再用一个双线性交互

Miracle8070 5726

【Go入门·预备知识】1.Go(Golang)是什么?——《跟老吕学Go语言》

在 Go 语言在 2010 年 1 月 8 日被 Tiobe(闻名于它的编程语言流行程度排名)宣布为 “2009 年年度语言” 后,引起各界很大的反响。在 2008 年年中,Go 语言的设计工作接近尾声,一些员工开始以全职工作状态投入到这个项目的编译器和运行实现上。Go语言有一个吉祥物,在会议、文档页面和博文中,大多会包含下图所示的 Go Gopher,这是才华横溢的插画家 Renee French 设计的,她也是 Go 设计者之一 Rob Pike 的妻子。,您的举手之劳将对我提供了无限的写作动力!

Python老吕的博客 1299

Python蓝色跳动的爱心(完整代码)

Python语言实现蓝色跳动的爱心的完整代码。 代码分析 这段代码使用了 库来创建一个动态的爱心图案,并在屏幕上显示带有动态效果的“我爱你”字样。以下是对这段代码的详细分析: 用于创建图形用户界面(GUI)。 用于生成随机数,主要用于控制爱心图案的扩散效果。 中的 , , , 用于数学计算,生成爱心形状和扩散效果。 包含了 等常量,用于控制控件的对齐方式。 2. 全局变量定义 , : 定义画布的大小。 , : 爱心的中心坐标。 : 用于定义爱心形状的缩放

AIGC 1921

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Go语言 并发与通道

Go语言 并发与通道

代码改变世界 783

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

13、go并发编程

【代码】12、go并发编程。

qq23001186的博客 1367

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

深度学习工具包 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")

golang中三种线程安全的MAP

123456789101112131415161718192021222324252627typestructmu Mutex// 基本上你可以把它看成一个安全的只读的map// 它包含的元素其实也是通过原子操作更新的,但是已删除的entry就需要加锁操作了// 包含需要加锁才能访问的元素// 包括所有在read字段中但未被expunged(删除)的元素以及新加的元素。

tiancityycf的专栏 4194

GoLang八股(Go并发)

本文摘要:文章系统介绍了并发编程中的核心概念,包括进程、线程和协程的区别,重点分析了Go语言的并发模型。主要内容包括:1) 进程是资源分配单位,线程是执行单位,协程是轻量级用户态线程;2) Go语言通过goroutine和channel实现并发,采用通信共享而非内存共享;3) 详细讲解了goroutine的生命周期控制、channel的用途及阻塞处理;4) 介绍了互斥锁(Mutex)的作用及其在并发控制中的应用。文章通过代码示例展示了Go语言中并发编程的实际应用,帮助理解并发机制的设计原理和实现方法。

Atticus的博客 879

go语言基础13——并发★★★

并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因。 Go语言中的并发编程 并发与并行 并发:同一时刻只执行一个任务,一个时间段内不断切换执行多个任务。 并行:同一时刻同时执行多个任务。 Go语言的并发通过goroutine实现。goroutine类似于线程,属于用户态的线程,我们可以根据需要创建成千上万个goroutine并发工作。goroutine是由Go语言的运行时(runtime)调度完成,而线程是由操作系统调度完成。 Go语言还提供c

一蓑烟雨任平生 797
上一篇: 一本《Redis 深度历险》,我能躺挣多少钱?
下一篇: 深入理解「分布式事务」
码洞
博客等级 码龄10年 41粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值