2 回答

TA貢獻1850條經驗 獲得超11個贊
好的,發生的情況是當您嘗試向通道添加內容時通道被阻塞。嘗試done
使用緩沖區(我使用 1)初始化通道,如下所示:
done = make(chan bool, 1)

TA貢獻1862條經驗 獲得超6個贊
您將看到OnConnectErrorHandler
在執行調用期間同步調用Connect()
.?在連接完全建立并且回調完成之前,該Connect()
函數不會啟動單獨的 goroutine 來處理 websocket 。OnConnected
因此,當您嘗試寫入無緩沖的通道時done
,您會阻塞最初調用該函數的同一個Goroutine,并且您自己會陷入僵局,因為沒有 Goroutine 能夠從通道讀取數據來解鎖您。run()
因此,您可以采用他的解決方案并將其轉換為緩沖通道,這將起作用,但我的建議是不要針對這種一次性標志行為寫入通道,而是使用信號發送close
。為每個要終止的條件定義一個通道run()
,并在相應的 websocket 處理函數中close
定義該條件發生時的通道。在底部run()
,您可以select
打開所有通道,并在第一個通道關閉時退出。它看起來像這樣:
package main
import "errors"
func run(appName string) (err error) {
? ? // first, define one channel per socket-closing-reason (DO NOT defer close these channels.)
? ? connectErrorChan := make(chan struct{})
? ? successDoneChan := make(chan struct{})
? ? surpriseDisconnectChan := make(chan struct{})
? ? // next, wrap calls to your handlers in a closure `https://gobyexample.com/closures`
? ? // that captures a reference to the channel you care about
? ? OnConnectErrorHandler := func(err error, socket gowebsocket.Socket) {
? ? ? ? MyOnConnectErrorHandler(connectErrorChan, err, socket)
? ? }
? ? OnDisconnectedHandler := func(err error, socket gowebsocket.Socket) {
? ? ? ? MyOnDisconectedHandler(surpriseDisconnectChan, err, socket)
? ? }
? ? // ... declare any other handlers that might close the connection here
? ? // Do your setup logic here
? ? // serviceURL, e := GetContext().getServiceURL(appName)
? ? // . . .
? ? // socket := gowebsocket.New(url)
? ? socket.OnConnectError = OnConnectErrorHandler
? ? socket.OnConnected = OnConnectedHandler
? ? socket.OnTextMessage = socketTextMessageHandler
? ? socket.OnDisconnected = OnDisconnectedHandler
? ? // Prepare and send your message here...
? ? // LogDebug("In %v func connecting to URL? %v", methodName, url)
? ? // . . .
? ? // socket.SendText(jsonStr)
? ? // now wait for one of your signalling channels to close.
? ? select { // this will block until one of the handlers signals an exit
? ? case <-connectError:
? ? ? ? err = errors.New("never connected? :( ")
? ? case <-successDone:
? ? ? ? socket.Close()
? ? ? ? LogDebug("mission accomplished! :) ")
? ? case <-surpriseDisconnect:
? ? ? ? err = errors.New("somebody cut the wires!? :O ")
? ? }
? ? if err != nil {
? ? ? ? LogDebug(err)
? ? }
? ? return err
}
// *Your* connect error handler will take an extra channel as a parameter
func MyOnConnectErrorHandler(done chan struct{}, err error, socket gowebsocket.Socket) {
? ? methodName := "OnConnectErrorHandler"
? ? LogDebug("Starting %v parameters [err = %v , socket = %v]", methodName, err, socket)
? ? LogInfo("Disconnected from server ")
? ? close(done) // signal we are done.
}
這有幾個優點:
1)你不需要猜測哪些回調發生在進程中,哪些回調發生在后臺 goroutine 中(并且你不必讓所有通道都緩沖“以防萬一”)
2) 在多個通道上進行選擇可以讓您找出退出的原因,并可能以不同的方式處理清理或日志記錄。
注意 1:如果您選擇使用close信令,則必須為每個源使用不同的通道,以避免可能導致通道從不同的 goroutine 關閉兩次的競爭條件(例如,當您返回響應時會發生超時,并且兩個處理程序都會觸發;關閉同一通道的第二個處理程序會導致panic。)這也是您不希望將defer close所有通道都放在函數頂部的原因。
注意2:與您的問題沒有直接關系,但是 - 您不需要關閉每個通道 - 一旦它的所有句柄超出范圍,無論通道是否已關閉,它都會被垃圾收集。
- 2 回答
- 0 關注
- 161 瀏覽
添加回答
舉報