以太坊中的事件机制Feed

    以太坊的事件框架,存在于目录go-ethereum/event中,它有两种事件框架实现,一种叫TypeMux(go-ethereum/event/event.go,现在已经基本弃用;另外一种叫Feed(go-ethereum/event/feed.go, 它是目前主要使用的对象。取代了前面说的event.go内部的TypeMux。

    以太坊的事件框架会把所有的订阅者放到一个集合中,每当事件框架收到某个事件的时候,就把通知所有订阅该事件的所有订阅者。由于TypeMux有可能会阻塞,所以通知订阅者可能会延时很久,估计这就是为什么弃用的原因吧。而Feed基本不会阻塞,一般会及时的把事件通知给订阅者,但需要给每种事件创建一个Feed,订阅或者发送事件则需要在不同的Feed上处理。下面主要介绍一下Feed的实现方式。

    Feed是一对多的事件框架。

  •     数据结构

    Feed的主要函数以及数据结构如下:
    Subscribe以及Send函数是包外可以调用的函数。

func (f *Feed) Subscribe(channel interface{}) Subscription

Subscribe函数添加一个订阅

func (f *Feed) Send(value interface{}) (nsent int) 

Send函数发送一个订阅事件。

type Feed struct {
	once      sync.Once        // ensures that init only runs once
	sendLock  chan struct{}    // sendLock has a one-element buffer and is empty when held.It protects sendCases.
	removeSub chan interface{} // interrupts Send
	sendCases caseList         // the active set of select cases used by Send

	// The inbox holds newly subscribed channels until they are added to sendCases.
	mu     sync.Mutex
	inbox  caseList
	etype  reflect.Type
	closed bool
}


once保证init函数只执行一次;sendLock是 “Send函数的锁。removeSub是“Send”以及“remove"之间“通讯”接口。sendCases是订阅者列表。inbox是刚刚加入的订阅者列表(Send函数会将inbox的订阅者移动到sendCases中);closed标识此订阅事件的状态。

type feedSub struct {
	feed    *Feed
	channel reflect.Value
	errOnce sync.Once
	err     chan error
}

    feedSub是Subscription的一种实现。Feed是管理各种feedSub。

     Subscription是个接口,定义在event/subscription.go文件中:
    Subscription提供两个函数:Err函数负责出错处理,Unsubscribe函数停止订阅。

func (sub *feedSub) Unsubscribe() 

Unsubscribe() 实现了订阅者退订某个事件;订阅事件的函数在上边已经实现了。

  • 实现方式

    实际运用中,我们主要的流程,就是订阅,发送事件,接收事件,取消订阅。

    订阅,订阅时需要一个channel作为参数传入。订阅函数也会校验传入的参数是否为chan以及通道的方向;然后构造一个feedSub数据作为返回值; 使用传入的channel生成了SelectCase,放入inbox,即将新加入的订阅者放入inbox里。 

 

    取消订阅,一般注册完成后,订阅者会获取一个Subscription,可以通过它取消订阅和读取通道错误。这时,订阅者会从inbox和sendCases中都被删除。

    发布事件,调用Feed.Send(chan x),通过加锁确保本类型事件只有一个发送协程正在进行,然后校验事件类型是否匹配,Feed会尝试给每个订阅者发送事件,如果订阅者阻塞,Feed就继续尝试给下一个订阅者发送,直到给每个订阅者发送事件,返回发送该事件的数量。

    接收事件,订阅者通过读取chan里的数据,实现事件的接收。

  • 如何使用

package main

import (
    "fmt"
    "sync"
    "github.com/ethereum/go-ethereum/event"
)

func main() {
    type bigevent struct{ number int }

    var f event.Feed
    var wg sync.WaitGroup

    ch := make(chan bitevent)
    sub := feed.Subscribe(ch)

    wg.Add(1)
    go func() {
        defer wg.Done()
        for event := range ch {
            fmt.Printf("Received: %#v\n", event.number)
        }
        sub.Unsubscribe()
    }()

    feed.Send(bigevent{5})

    close(ch)

    wg.Wait()
}

      我们设置了事件bigevent,创建了feed,然后订阅feed;开启协程监听通道,看是否有事件推送,等到通多关闭后,取消订阅;

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值