doujuan2688 2018-03-23 07:48
浏览 68
已采纳

从其他线程读取值

I'm writing software in Go that does a lot of parallel computing. I want to collect data from worker threads and I'm not really sure how to do it in a safe way. I know that I could use channels but in my scenario they make it more complicated since I have to somehow synchronize messages (wait until every thread sent something) in the main thread.

Scenario

The main thread creates n Worker instances and launches their work() method in a goroutine so that the workers each run in their own thread. Every 10 seconds the main thread should collect some simple values (e.g. iteration count) from the workers and print a consolidated statistic.

Question

Is it safe to read values from the workers? The main thread will only read values and each individual thread will write it's own values. It would be ok if the values are a few nanoseconds off while reading.

Any other ideas on how to implement this in an easy way?

  • 写回答

1条回答 默认 最新

  • dongxieting9623 2018-03-23 08:15
    关注

    In Go no value is safe for concurrent access from multiple goroutines without synchronization if at least one of the accesses is a write. Your case meets the conditions listed, so you must use some kind of synchronization, else the behavior would be undefined.

    Channels are used if goroutine(s) want to send values to another. Your case is not exactly this: you don't want your workers to send updates in every 10 seconds, you want your main goroutine to fetch status in every 10 seconds.

    So in this example I would just protect the data with a sync.RWMutex: when the workers want to modify this data, they have to acquire a write lock. When the main goroutine wants to read this data, it has to acquire a read lock.

    A simple implementation could look like this:

    type Worker struct {
        iter    int
        iterMux sync.RWMutex
    }
    
    func (w *Worker) Iter() int {
        w.iterMux.RLock()
        defer w.iterMux.RUnlock()
        return w.iter
    }
    
    func (w *Worker) setIter(n int) {
        w.iterMux.Lock()
        w.iter = n
        w.iterMux.Unlock()
    }
    
    func (w *Worker) incIter() {
        w.iterMux.Lock()
        w.iter++
        w.iterMux.Unlock()
    }
    

    Using this example Worker, the main goroutine can fetch the iteration using Worker.Iter(), and the worker itself can change / update the iteration using Worker.setIter() or Worker.incIter() at any time, without any additional synchronization. The synchronization is ensured by the proper use of Worker.iterMux.

    Alternatively for the iteration counter you could also use the sync/atomic package. If you choose this, you may only read / modify the iteration counter using functions of the atomic package like this:

    type Worker struct {
        iter int64
    }
    
    func (w *Worker) Iter() int64 {
        return atomic.LoadInt64(&w.iter)
    }
    
    func (w *Worker) setIter(n int64) {
        atomic.StoreInt64(&w.iter, n)
    }
    
    func (w *Worker) incIter() {
        atomic.AddInt64(&w.iter, 1)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大