在结构体内部关闭通道

huangapple go评论85阅读模式
英文:

Closing Channel Inside of a Struct

问题

我一直在尝试查看关于关闭通道的现有帖子,但似乎找不到我要找的确切内容。我在一个结构体中有两个通道。在创建完通道后,我尝试立即运行defer close(channelName),但通道立即关闭并出现错误。如果我不处理关闭通道的问题,代码可以正常运行,但无法正常关闭,我必须使用ctrl z来挂起程序,因为在使用ctrl c后程序仍在运行。以下是代码的重要部分:

总结一下,结构体KrakenClient有一个类型为WebsocketClient的字段,其中包含2个WebSockets和2个通道。在KrakenClient结构体上调用InitWebSocketClient函数会创建这两个通道并连接到WS服务器。一旦连接到服务器,我开始解组所有响应并将这些响应发送到一个通道中。然后,我订阅特定的端点,并开始“监听”响应(实际上是遍历数据并根据某些条件将其添加到传递给监听函数的ohlcMap变量中)。我只是不明白在哪里应该关闭这些通道。我是否需要在KrakenClient结构体上创建一个Close函数,在关闭通道时使用defer调用它?如果是这样,它应该放在哪里?感谢任何帮助!

英文:

I've been trying to look through existing posts about closing a channel, but I can't seem to find exactly what I'm looking for. I have two channels inside of a struct. After making the channels, I tried to run defer close(channelName) immediately after, but the channels immediately closed and I got an error. If I don't deal with closing the channels, the code runs fine, but doesn't shut down gracefully and I have to use ctrl z to suspend the program, since it's still running after using ctrl c. Here are the important parts of the code:

type WebsocketClient struct {
	pubSocket  ws_client.Socket
	privSocket ws_client.Socket
	pubChan    chan interface{}
	privChan   chan interface{}
}

type KrakenClient struct {
	WebSocket WebsocketClient
	Testing   bool
}

func (client *KrakenClient) initChannels() {
	client.WebSocket.pubChan = make(chan interface{})
	client.WebSocket.privChan = make(chan interface{})

	//defer close(client.WebSocket.pubChan)
	//defer close(client.WebSocket.privChan)
}

func (client *KrakenClient) InitWebSocketClient(wg *sync.WaitGroup, testing bool) {
	client.initTesting(testing)
	client.initChannels()
	client.startWebSocketConnection(wg)
}

func (client *KrakenClient) PubDecoder(wg *sync.WaitGroup, ctx context.Context) {
	wg.Add(1)
	defer wg.Done()
	defer client.WebSocket.pubSocket.Close()

	if err := PubSocketGuard(client.WebSocket); err != nil { // guard clause checker. makes sure i'm actually using a public WebSocket
		panic(err)
	}

	var res interface{}

	ws_client.ReceiveLocker(&client.WebSocket.pubSocket)
	client.WebSocket.pubSocket.OnTextMessage = func(message string, socket ws_client.Socket) {
		res = ws_client.PubJsonDecoder(message, client.Testing)
		client.WebSocket.pubChan <- res
	}
	ws_client.ReceiveUnlocker(&client.WebSocket.pubSocket)

	<-ctx.Done()
	log.Println("closing public socket")
	return
}

func (client *KrakenClient) PubListen(wg *sync.WaitGroup, ctx context.Context, ohlcMap *types.OHLCVals) {
	wg.Add(1)
	defer wg.Done()

	for c := range client.WebSocket.pubChan {
		switch v := c.(type) {
		// More code here. Not important to the channel problem
	}
	<-ctx.Done()
}

func main() {
	var testing bool = true

	comms := make(chan os.Signal, 1)
	signal.Notify(comms, os.Interrupt, syscall.SIGTERM)
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	var wg sync.WaitGroup

	kraken := &kraken_client.KrakenClient{}
	kraken.InitWebSocketClient(&wg, testing)
	go kraken.PubDecoder(&wg, ctx)
	kraken.SubscribeToOHLC(&wg, []string{"BTC/USD"}, 5)

	ohlcMap := types.OHLCVals{}

	go kraken.PubListen(&wg, ctx, &ohlcMap)

	<-comms
	cancel()
	wg.Wait()

}

In summary, struct KrakenClient has a type WebsocketClient, which holds 2 WebSockets and 2 channels. Calling the InitWebSocketClient func on the KrakenClient struct creates the two channels and connects to the WS server. Once connected to the server, I start to unmarshal all responses and send those responses to a channel. I then subscribe to a specific endpoint, and start to "listen" to the responses (actually go through the data and add it to the ohlcMap variable that's passed to the listen func depending on certain circumstances). I just don't understand where I should be closing the channels. Do I need to create a Close function on my KrakenClient struct that defers when the channels are closed? If so, where would it even go? Appreciate any help!

答案1

得分: 1

你必须在主函数中调用defer,因为当你在initChannels函数中调用defer时,它会在创建完通道后立即关闭通道。
defer语句总是在函数(在你的代码中是initChannels函数)返回后执行。

你可以编写一个关闭函数来关闭通道,并在主函数中调用它,如下所示:

func (client *KrakenClient) closeChannels() {
    close(client.WebSocket.pubChan)
    close(client.WebSocket.privChan)
}

func (client *KrakenClient) initChannels() {
    client.WebSocket.pubChan = make(chan interface{})
    client.WebSocket.privChan = make(chan interface{})
}

func main() {
    ...
    kraken.InitWebSocketClient(&wg, testing)
    defer kraken.closeChannels()
    ...
}
英文:

You must call defer in main func because when you call defer in initChannels func it's immediately close your channels after making.
The defer always execute when the function (initChannels in your code) has been return.

you can write a closing function for close the channels and call it on main func like as:

func (client *KrakenClient) closeChannels() {
	close(client.WebSocket.pubChan)
	close(client.WebSocket.privChan)
}

func (client *KrakenClient) initChannels() {
	client.WebSocket.pubChan = make(chan interface{})
	client.WebSocket.privChan = make(chan interface{})
}

func main() {
	...
	kraken.InitWebSocketClient(&wg, testing)
	defer kraken.closeChannels()
	...
}

huangapple
  • 本文由 发表于 2022年7月24日 14:44:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/73096316.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定