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

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

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.

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:

确定