If the intent is to only store the counter in the value, STM is more expensive than necessary. STM costs at least one extra round trip, and more if there are read conflicts.
Using the key version is more efficient and faster:
Increment the counter 500 times atomically:
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 500; i++ {
go func() {
defer wg.Done()
cli.Put(context.TODO(), "key", "")
}()
}
wg.Wait()
Read the counter:
func getCounter(cli *clientv3.Client) int64 {
resp, err := cli.Get(context.TODO(), "key")
if err != nil { panic(err) }
if len(resp.Kvs) == 0 { return 0 }
return resp.Kvs[0].Version