在Golang中,delete操作是否保证从哈希表中删除元素?

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

is delete guaranteed to delete from a hash in golang?

问题

我有一个像这样的哈希表:

  1. var TransfersInFlight map[string]string = make(map[string]string)

在发送文件之前,我会为其创建一个键,存储并发送它,然后删除它:

  1. timeKey := fmt.Sprintf("%v",time.Now().UnixNano())
  2. TransfersInFlight[timeKey] = filename
  3. total, err := sendTheFile(filename)
  4. delete(TransfersInFlight, timeKey)

也就是说,在发送文件的过程中,哈希表中有一个带有时间戳的键指向文件名。

函数sendTheFile要么正常工作,要么出现错误,但从不抛出堆栈跟踪异常并导致整个程序崩溃,因此应该始终调用以下代码行:

  1. delete(TransfersInFlight, timeKey)

然而,我有时会发现有些情况下似乎从未调用过这行代码,导致文件永远停留在TransfersInFlight中。这是怎么可能的?

英文:

I have a hash like this:

  1. 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:

  1. timeKey := fmt.Sprintf("%v",time.Now().UnixNano())
  2. TransfersInFlight[timeKey] = filename
  3. total, err := sendTheFile(filename)
  4. 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:

  1. 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来管理计数,一种方法是:

  1. import "sync/atomic"
  2. var TransferChan chan int32
  3. var TransfersInFlight int32
  4. func TransferManager() {
  5. TransfersInFlight = 0
  6. for delta := range TransferChan {
  7. // 你可能可以安全地使用+=,但是最好确保一次只有一个访问。
  8. atomic.AddInt32(&TransfersInFlight, delta)
  9. }
  10. }

这样,你只需要执行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:

  1. import "sync/atomic"
  2. var TransferChan chan int32
  3. var TransfersInFlight int32
  4. func TransferManager() {
  5. TransfersInFlight = 0
  6. for delta := range TransferChan {
  7. // You're *probably* safe just using +=, but, you know...
  8. atomic.AddInt32(&TransfersInFlight, delta)
  9. }
  10. }

That way, you only need to do go TransferManager() and then pass your increments and decrements over the TransferChan channel.

huangapple
  • 本文由 发表于 2016年10月7日 06:07:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/39906363.html
匿名

发表评论

匿名网友

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

确定