• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
思念以南
博客园    首页    新随笔    联系   管理    订阅  订阅

空结构体 chan struct{}

目录
  • 空结构体
  • chan struct{}
  • 常用用法
  • 使用场景
  • 带缓冲的chan 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
0人点赞
Go

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被关闭了或者为空。

使用案例:

func worker(ch chan struct{}) {
	// Receive a message from the main program.
	<-ch
	println("roger")

	// Send a message to the main program.
	close(ch)
}

func main() {
	ch := make(chan struct{})
	go worker(ch)

	// Send a message to a worker.
	ch <- struct{}{}

	// Receive a message from the worker.
	<-ch
	println("roger")
	// Output:
	// roger
	// roger
}

原文链接:https://blog.csdn.net/weixin_44328662/article/details/86501900

posted @ 2022-05-10 14:28  思念以南  阅读(286)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3