@@ -3,6 +3,7 @@ package redis_test
33import (
44 "context"
55 "fmt"
6+ "sync"
67 "testing"
78 "time"
89
@@ -104,6 +105,61 @@ func benchmarkHSETOperations(b *testing.B, rdb *redis.Client, ctx context.Contex
104105 b .ReportMetric (float64 (avgTimePerOpMs ), "ms" )
105106}
106107
108+ // benchmarkHSETOperationsConcurrent performs the actual HSET benchmark for a given scale
109+ func benchmarkHSETOperationsConcurrent (b * testing.B , rdb * redis.Client , ctx context.Context , operations int ) {
110+ hashKey := fmt .Sprintf ("benchmark_hash_%d" , operations )
111+
112+ b .ResetTimer ()
113+ b .StartTimer ()
114+ totalTimes := []time.Duration {}
115+
116+ for i := 0 ; i < b .N ; i ++ {
117+ b .StopTimer ()
118+ // Clean up the hash before each iteration
119+ rdb .Del (ctx , hashKey )
120+ b .StartTimer ()
121+
122+ startTime := time .Now ()
123+ // Perform the specified number of HSET operations
124+
125+ wg := sync.WaitGroup {}
126+ wg .Add (operations )
127+ timesCh := make (chan time.Duration , operations )
128+ for j := 0 ; j < operations ; j ++ {
129+ go func (j int ) {
130+ defer wg .Done ()
131+ field := fmt .Sprintf ("field_%d" , j )
132+ value := fmt .Sprintf ("value_%d" , j )
133+
134+ err := rdb .HSet (ctx , hashKey , field , value ).Err ()
135+ if err != nil {
136+ b .Fatalf ("HSET operation failed: %v" , err )
137+ }
138+ timesCh <- time.Since (startTime ))
139+ }(j )
140+ wg .Wait ()
141+ close (timesCh )
142+ for d := range timesCh {
143+ totalTimes = append (totalTimes , d )
144+ }
145+ }
146+ }
147+
148+ // Stop the timer to calculate metrics
149+ b .StopTimer ()
150+
151+ // Report operations per second
152+ opsPerSec := float64 (operations * b .N ) / b .Elapsed ().Seconds ()
153+ b .ReportMetric (opsPerSec , "ops/sec" )
154+
155+ // Report average time per operation
156+ avgTimePerOp := b .Elapsed ().Nanoseconds () / int64 (operations * b .N )
157+ b .ReportMetric (float64 (avgTimePerOp ), "ns/op" )
158+ // report average time in milliseconds from totalTimes
159+ avgTimePerOpMs := totalTimes [0 ].Milliseconds () / int64 (len (totalTimes ))
160+ b .ReportMetric (float64 (avgTimePerOpMs ), "ms" )
161+ }
162+
107163// BenchmarkHSETPipelined benchmarks HSET operations using pipelining for better performance
108164func BenchmarkHSETPipelined (b * testing.B ) {
109165 ctx := context .Background ()
@@ -134,6 +190,36 @@ func BenchmarkHSETPipelined(b *testing.B) {
134190 }
135191}
136192
193+ func BenchmarkHSET_Concurrent (b * testing.B ) {
194+ ctx := context .Background ()
195+
196+ // Setup Redis client
197+ rdb := redis .NewClient (& redis.Options {
198+ Addr : "localhost:6379" ,
199+ DB : 0 ,
200+ PoolSize : 1000 ,
201+ })
202+ defer rdb .Close ()
203+
204+ // Test connection
205+ if err := rdb .Ping (ctx ).Err (); err != nil {
206+ b .Skipf ("Redis server not available: %v" , err )
207+ }
208+
209+ // Clean up before and after tests
210+ defer func () {
211+ rdb .FlushDB (ctx )
212+ }()
213+
214+ scales := []int {1 , 10 , 100 , 1000 , 10000 , 100000 }
215+
216+ for _ , scale := range scales {
217+ b .Run (fmt .Sprintf ("HSET_%d_operations_concurrent" , scale ), func (b * testing.B ) {
218+ benchmarkHSETOperationsConcurrent (b , rdb , ctx , scale )
219+ })
220+ }
221+ }
222+
137223// benchmarkHSETPipelined performs HSET benchmark using pipelining
138224func benchmarkHSETPipelined (b * testing.B , rdb * redis.Client , ctx context.Context , operations int ) {
139225 hashKey := fmt .Sprintf ("benchmark_hash_pipelined_%d" , operations )
0 commit comments