go语言-空结构体/ chan struct{}-程序员宅基地

技术标签: Go  go  空结构体  

空结构体 struct{}

空结构体的宽度是0,占用了0字节的内存空间。

var s struct{
    }
fmt.Println(unsafe.Sizeof(s)) // prints 0

由于空结构体占用0字节,那么空结构体也不需要填充字节。所以空结构体组成的组合数据类型也不会占用内存空间。

 type S struct {
    

        A struct{
    }

        B struct{
    }

    }

    var s S

    fmt.Println(unsafe.Sizeof(s)) // prints 0

chan struct{}

通过消息来共享数据是golang的一种设计哲学,channel则是这种哲理的体现。

golang中的空结构体 channel := make(chan struct{})
特点

  • 省内存,尤其在事件通信的时候。
  • struct零值就是本身,读取close的channel返回零值

常用用法

通常struct{}类型channel的用法是使用同步,一般不需要往channel里面写数据,只有读等待,而读等待会在channel被关闭的时候返回。

type Miner struct {
    
	api api.FullNode

	epp gen.WinningPoStProver

	lk       sync.Mutex
	address  address.Address
	stop     chan struct{
    }
	stopping chan struct{
    }

	waitFunc waitFunc

	lastWork *MiningBase

	minedBlockHeights *lru.ARCCache
}

stop 它是一个管道chan,内部的数据类型是struct{}。

单独拿struct{}来说,我们熟悉type Name struct{a int, b bool}这样去定义一个结构体的类型,其实struct{…}就是定义结构体,和map[string]int这种定义是一样的,type只是给它取了一个别名。 总结: 实际上struct{}就是一种普通数据类型,只是没有具体的值而已。

注意,channel对象一定要make出来才能使用。, 如下,make后赋值给m

func (m *Miner) Start(ctx context.Context) error {
    
	m.lk.Lock()
	defer m.lk.Unlock()
	if m.stop != nil {
    
		return fmt.Errorf("miner already started")
	}
	m.stop = make(chan struct{
    })
	go m.mine(context.TODO())
	return nil
}

func (m *Miner) Stop(ctx context.Context) error {
    
	m.lk.Lock()
	defer m.lk.Unlock()

	m.stopping = make(chan struct{
    })
	stopping := m.stopping
	close(m.stop)

	select {
    
	case <-stopping:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

使用场景
首先事件通知,可以通过写入 通知其他协程,但是只能通知一个。

channel := make(chan struct{
    })
go func() {
    
    // ... do something
    channel <- struct{
    }{
    }
}()
fmt.Println(<-channel)

和close进行配合,通知所有相关协程。

在读入被close的channel返回零值,正常的协程是读取不到这个close的。
close之后,所有协程都可以读到。

比较经典的例子就是用于stopChan作为停止channel通知所有协程。

在下面的例子中 我们可以通过s.Stop()通知所有的serverHandler协程停止工作,并且等待他们正常退出。

type Server struct {
    
    serverStopChan chan struct{
    }
    stopWg         sync.WaitGroup
}
func (s *Server) Stop() {
    
    if s.serverStopChan == nil {
    
        panic("gorpc.Server: server must be started before stopping it")
    }
    close(s.serverStopChan)
    s.stopWg.Wait()
    s.serverStopChan = nil
}
func serverHandler(s *Server){
    
    for {
    
        select {
    
        case <-s.serverStopChan:
            return
        default:
            // .. do something
        }
    }
}

带缓冲的chan struct{}数据读写

另外也可以定义带缓冲的channel

package main

import (
    "time"
    "log"
)

var ch chan struct{
    } = make(chan struct{
    }, 2)

func foo() {
    
    ch <- struct{
    }{
    }
    log.Println("foo() 000");
    ch <- struct{
    }{
    }
    log.Println("foo() 111");
    time.Sleep(5 * time.Second)
    log.Println("foo() 222");
    close(ch)
    log.Println("foo() 333");
}

func main() {
    
    var b struct{
    }
 
    log.Println("main() 111");
    go foo()
    log.Println("main() 222");
    a := <-ch
    log.Println("main() 333", a);
    b  = <-ch
    log.Println("main() 444", b);
    c := <-ch
    log.Println("main() 555", c);
}

<-ch用来从channel ch中接收数据,这个表达式会一直被block,直到有数据可以接收。

从一个nil channel中接收数据会一直被block。(往nil channel中发送数据会一致被阻塞着。)

从一个被close的channel中接收数据不会被阻塞,而是立即返回,接收完已发送的数据后会返回元素类型的零值(zero value)。

如前所述,你可以使用一个额外的返回参数来检查channel是否关闭。

x, ok := <-ch
x, ok = <-ch
var x, ok = <-ch

如果OK 是false,表明接收的x是产生的零值,这个channel被关闭了或者为空。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/inthat/article/details/106917358

智能推荐

记一次ANR文件的导出_adb命令导出高版本的anr文件-程序员宅基地

文章浏览阅读9.7k次,点赞9次,收藏32次。文章目录1.老版Android系统 anr的导出2.高版本系统 导出3.ANR的缘由1.老版Android系统 anr的导出在项目目录下或app下运行命令: adb pull data/anr/traces.txt测试了华为p7(Android 5.1.1)和荣耀v10(Android 9),发现都能正常导出。但是遇到华为mate10、mate10 pro 一直都导出失败。adb: e..._adb命令导出高版本的anr文件

Oracle RAC启动及关闭步骤-程序员宅基地

文章浏览阅读757次。Oracle RAC的关闭及启动,需要严格按照步骤来执行,以下就以一套实际的系统为例,来介绍RAC的关闭及启动过程:环境说明主机名实例名监听端口字符集db-node1orcl11521ZHS16GBKdb-node2orcl21521ZHS16GBK关闭顺序:关闭数据库(实例)->..._ora...c2.lsnr 启动

Matlab中interp1()和interp2()的用法_插值要求每个网格维度至少有两个采样点。-程序员宅基地

文章浏览阅读1w次,点赞7次,收藏30次。1.一维插值interp1()yi=interp1(x,y,xi,method)其中,x、y为已知的数据点;xi为想要插值数据点的横坐标,返回对应的纵坐标yi;method为插值方法,总共有四种:1)‘nearest’:最近邻点插值;2)‘linear’:线性插值;3)‘spline’:三次样条插值;4)‘pchip’:保形分段三次插值。2.二维插值interp2()zi=inte..._插值要求每个网格维度至少有两个采样点。

Wix 快速开发安装包程序 (二)安装行为-程序员宅基地

文章浏览阅读136次。上一小节,主要介绍了构建最小级别的安装包,这个安装包所做的事情很简单,主要是打包好一些文件,然后放到用户机器的某个位置下面。这个小节,主要是总结安装过程的各种行为如何使用Wix编写。一、写注册表安装过程经常会给注册表写东西,这个方法是通过 RegistryKey 元素实现的,通常用 Root 和 Key 来确定写注册表的位置,然后子元素RegistryValue 来在这个位置下面写一条一条的项目,Name 和 Value 来确定这一项。<DirectoryRef Id="TARGETDIR"

雨后小故事-1_雨后小故事gti图-程序员宅基地

文章浏览阅读1.7w次。小白兔有一家糖果铺,小老虎有一个冰淇淋机。兔妈妈告诉小白兔,如果你喜欢一个人呐,就给他一颗糖。小白兔喜欢上了小老虎,那么那么喜欢,忍不住就把整个店子送给了他。回家后兔妈妈问她,那小老虎喜欢你吗?小白兔直点头,妈妈说,那他为什么不给你吃个冰淇淋呢?2.小白兔说,他是要给我来着,我说我不爱吃。兔妈妈说,那你真的不爱吃吗?有七种口味呢,巧克力味道的里面还有你最爱吃的杏仁啊。小白兔用脚划拉着地板,喃喃的说,其实我也没吃过,只是就想着把糖给他了。3..._雨后小故事gti图

ubuntu中运用docker搭建dvwa漏洞靶场环境_ubuntu18 dvwa靶场搭建-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏11次。实验用到的工具ubuntu火狐浏览器xshell5docker环境第一步打开ubuntu系统,xshell登陆账号密码连接。第二步下载lamp映像 docker pull vuldocker/lamp查看映像是否下载成功 docker images注意:vuldocker/lamp映像包括(php+apache+mysql),只需要下载dvwa源码即可,后面给出dvwa源..._ubuntu18 dvwa靶场搭建

随便推点

CentOS7系统操作httpd服务 - 开机启动/重启/查看状态_httpd重启-程序员宅基地

文章浏览阅读5.7w次,点赞8次,收藏45次。操作部署某个环境的时候使用的是CentOS7版本,然后在需要启动httpd服务的时候惯性的使用service httpd start命令,但是提示有"/bin/systemctl start httpd.service"问题。看来系统变动之后一些操作命令还是有些变化的。当然,为了兼容性,我们原来习惯使用的service命令在CentOS7中仍然是可以使用的,它会重定向命令到新的syste_httpd重启

R语言时间序列分析-根据aic值选择arima模型_r语言aic检验代码-程序员宅基地

文章浏览阅读9.1k次,点赞6次,收藏49次。在上一篇中,探讨了R语言时间序列分析常用步骤,如何比对AIC值判断最优模型?代码和解释如下:#WWWusage是datasets包自带的每分钟通过服务器连接到因特网的用户数的长度为100的时间序列数据require(graphics) #画图判断平稳性,调用plot和par函数win.graph(); plot(WWWusage) #明显带趋势,需要差分work <- diff(WWWusage,1,1) #对其进行1阶差分,滞后期数lag为1win.graph(); par(mfr_r语言aic检验代码

[深度学习论文笔记DoDNet: Learning to segment multi-organ and tumors from multiple partially labeled datasets-程序员宅基地

文章浏览阅读5.2k次,点赞12次,收藏27次。DoDNet: Learning to segment multi-organ and tumors from multiple partially labeled datasetsDoDNet:学习从多个部分标记数据集中分割多器官和肿瘤Jul 2021CVPR 2021论文:https://arxiv.org/abs/2011.10217代码: https://github.com/jianpengz/DoDNet摘要:  由于在体素水平标注3D医学图像需要大量的劳动力和专业知识,大多数基准_dodnet

RBAC新解:基于资源的权限管理(Resource-Based Access Control)_rbac基于资源的访问控制-程序员宅基地

文章浏览阅读442次,点赞2次,收藏2次。引用自 链接什么是角色当说到程序的权限管理时,人们往往想到角色这一概念。角色是代表一系列可执行的操作或责任的实体,用于限定你在软件系统中能做什么、不能做什么。用户帐号往往与角色相关联,因此,一个用户在软件系统中能做什么取决于与之关联的各个角色。例如,一个用户以关联了”项目管理员”角色的帐号登录系统,那这个用户就可以做项目管理员能做的所有事情――如列出项目中的应用、管理项目组成员、产生项目..._rbac基于资源的访问控制

CSS3动画库 Animate.css-程序员宅基地

文章浏览阅读68次。传送门一个c3动画库,收藏一下

Python画高斯分布图 (2D, 3D)_python绘制3d二维高斯核函数-程序员宅基地

文章浏览阅读2.1w次,点赞21次,收藏107次。使用Python画高斯概率分布图_python绘制3d二维高斯核函数

推荐文章

热门文章

相关标签