英文:
is delete guaranteed to delete from a hash in golang?
问题
我有一个像这样的哈希表:
var TransfersInFlight map[string]string = make(map[string]string)
在发送文件之前,我会为其创建一个键,存储并发送它,然后删除它:
timeKey := fmt.Sprintf("%v",time.Now().UnixNano())
TransfersInFlight[timeKey] = filename
total, err := sendTheFile(filename)
delete(TransfersInFlight, timeKey)
也就是说,在发送文件的过程中,哈希表中有一个带有时间戳的键指向文件名。
函数sendTheFile
要么正常工作,要么出现错误,但从不抛出堆栈跟踪异常并导致整个程序崩溃,因此应该始终调用以下代码行:
delete(TransfersInFlight, timeKey)
然而,我有时会发现有些情况下似乎从未调用过这行代码,导致文件永远停留在TransfersInFlight中。这是怎么可能的?
英文:
I have a hash like this:
var TransfersInFlight map[string]string = make(map[string]string)
And before I send a file I make a key for it store, send it, delete it:
timeKey := fmt.Sprintf("%v",time.Now().UnixNano())
TransfersInFlight[timeKey] = filename
total, err := sendTheFile(filename)
delete(TransfersInFlight, timeKey)
i.e. during the time it takes to send the file, there is a key in the hash with a timestamp pointing to the filename.
the func sendTheFile
always either works, or has an err but never throws a stacktrace exception and crashes the whole program so the line:
delete(TransfersInFlight, timeKey)
should be called 100% of the time. And yet, I sometimes find cases where it's like this line was never called and the file is stuck in TransfersInFlight forever. How is this possible?
答案1
得分: 1
地图不适合并发访问。我建议使用互斥锁来控制地图的访问,或者使用一个goroutine来读取"op"结构体的通道,或者使用一个"add"通道和一个"delete"通道。
如果你确定要使用goroutine来管理计数,一种方法是:
import "sync/atomic"
var TransferChan chan int32
var TransfersInFlight int32
func TransferManager() {
TransfersInFlight = 0
for delta := range TransferChan {
// 你可能可以安全地使用+=,但是最好确保一次只有一个访问。
atomic.AddInt32(&TransfersInFlight, delta)
}
}
这样,你只需要执行go TransferManager()
,然后通过TransferChan
通道传递增量和减量。
英文:
Maps are not safe for concurrent access. I would do this either using a mutex to moderate map access or having a goroutine reading either a channel of "op" structs or have a "add" channel and a "delete" channel.
You're probably safe having multiple read-only accesses concurrently, but once you have writes in the mix, you really want to ensure you only have one access at a time.
If you are set on using a goroutine to manage the count, one way would be something like:
import "sync/atomic"
var TransferChan chan int32
var TransfersInFlight int32
func TransferManager() {
TransfersInFlight = 0
for delta := range TransferChan {
// You're *probably* safe just using +=, but, you know...
atomic.AddInt32(&TransfersInFlight, delta)
}
}
That way, you only need to do go TransferManager()
and then pass your increments and decrements over the TransferChan
channel.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论