dongshan2680 2019-07-19 09:07
浏览 32

基于异步回调的API上的同步API包装器

I'm using the pion/webrtc Go library in my project and found this problem that the callback-based API the library provides (which mirrors the JavaScript API of WebRTC) can be awkward to use in Go.

For example, doing the following

conn.OnTrack(func(...) { ... })
conn.OnICEConnectionStateChange(func(...) { ... })

is typical in JavaScript, but in Go, this has a few problems:

  • This API makes it easy to introduce data race, if the callbacks are called in parallel.
  • The callback-based API propagates to other part of the codebase and makes everything takes callbacks.

What's the conventional way to handle this situation in Go? I'm new to Go and I read that synchronous API is preferred in Go because Goroutines are cheap. So perhaps one possible design is to use a channel to synchronize the callbacks:

msgChan := make(chan Msg)
// or use a separate channel for each type of event?

conn.OnTrack(func(...) {
  msgChan <- onTrackMsg
})
conn.OnICEConnectionStateChange(func(...) {
  msgChan <- onStateChangeMsg
})

for {
  msg := <-msgChan
  // do something depending on the type of msg
}

I think forcing synchronization with channels basically mimics the single-threaded nature of JavaScript.

Anyway, how do people usually model event-driven workflow in Go?

  • 写回答

1条回答 默认 最新

  • doucu7330 2019-07-19 09:11
    关注

    No need for a channel. Just wrap your async/callback code in a single function that waits for a response, and use a WaitGroup (you could use a channel here instead, but a WaitGroup is much easier):

    func DoSomething() (someType, error) {
        var result SomeType
        var err error
        wg := sync.WaitGroup{}
        wg.Add(1)
        StartAsyncProcess(func() {
            // This is the call back that gets called eventually
            defer wg.Done()
            result = /* Set the result */
            err = /* and/or set the error */
        })
        wg.Wait() // Wait until the callback is called, and exits
        return result, err  // And finally return our values
    }
    

    You may need/wish to add additional locks or synchronization in the callback, if necessary in your case, if your callback relies on or modifies shared state.

    评论

报告相同问题?

悬赏问题

  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题