eldar.sahipov
3 months ago
3 changed files with 214 additions and 58 deletions
@ -0,0 +1,158 @@ |
|||
package cache |
|||
|
|||
import ( |
|||
"context" |
|||
"errors" |
|||
"fmt" |
|||
"math/rand" |
|||
"sync" |
|||
"testing" |
|||
"time" |
|||
) |
|||
|
|||
func BenchmarkCache_ConcurrentUpsertAndGet(b *testing.B) { |
|||
ctx := context.Background() |
|||
expiredInterval := 10 * time.Minute // Произвольно выбранный интервал истечения срока действия
|
|||
runGCInterval := 1 * time.Minute // Произвольно выбранный интервал запуска сборщика мусора
|
|||
|
|||
// Инициализация кэша
|
|||
Init(ctx, expiredInterval, runGCInterval) |
|||
c := Cache() |
|||
|
|||
var wg sync.WaitGroup |
|||
|
|||
// Количество операций для каждого типа (запись и чтение)
|
|||
operationsCount := 100000 |
|||
|
|||
b.ResetTimer() |
|||
// Запуск горутин для записи
|
|||
for i := 0; i < operationsCount; i++ { |
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", i) |
|||
_, err := c.Upsert(key, func() (interface{}, error) { |
|||
return fmt.Sprintf("value%d", i), nil |
|||
}, 5*time.Minute) // Используем 5 минут как интервал обновления
|
|||
if err != nil { |
|||
b.Errorf("Failed to upsert item: %s", err) |
|||
} |
|||
}(i) |
|||
} |
|||
|
|||
// Запуск горутин для чтения
|
|||
for i := 0; i < operationsCount; i++ { |
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", i) |
|||
_, err := c.Get(key) |
|||
if err != nil && !errors.Is(err, ErrorKeyNotFound) { |
|||
b.Errorf("Failed to get item: %s", err) |
|||
} |
|||
}(i) |
|||
} |
|||
|
|||
wg.Wait() // Ожидание завершения всех горутин
|
|||
} |
|||
|
|||
// BenchmarkCache_ConcurrentUpsert бенчмарк для многопоточной операции Upsert.
|
|||
func BenchmarkCache_ConcurrentUpsert(b *testing.B) { |
|||
ctx := context.Background() |
|||
Init(ctx, 10*time.Minute, 1*time.Minute) |
|||
c := Cache() |
|||
|
|||
b.ResetTimer() |
|||
var wg sync.WaitGroup |
|||
for i := 0; i < b.N; i++ { |
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
_, err := c.Upsert(fmt.Sprintf("key%d", i), func() (interface{}, error) { |
|||
return fmt.Sprintf("value%d", i), nil |
|||
}, 5*time.Minute) |
|||
if err != nil { |
|||
b.Errorf("Failed to upsert item: %s", err) |
|||
} |
|||
}(i) |
|||
} |
|||
wg.Wait() |
|||
} |
|||
|
|||
func BenchmarkCache_ConcurrentGet2(b *testing.B) { |
|||
ctx := context.Background() |
|||
Init(ctx, 10*time.Minute, 1*time.Minute) |
|||
c := Cache() |
|||
|
|||
// Предварительно заполняем кэш данными для чтения
|
|||
for i := 0; i < 100000; i++ { |
|||
key := fmt.Sprintf("key%d", i) |
|||
c.Upsert(key, func() (interface{}, error) { |
|||
return fmt.Sprintf("value%d", i), nil |
|||
}, 5*time.Minute) |
|||
} |
|||
|
|||
b.ResetTimer() |
|||
b.RunParallel(func(pb *testing.PB) { |
|||
for pb.Next() { |
|||
_, err := c.Get(fmt.Sprintf("key%d", rand.Intn(10000))) |
|||
if err != nil { |
|||
b.Errorf("Failed to get item: %s", err) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
|
|||
func BenchmarkCache_ProductionLike(b *testing.B) { |
|||
ctx := context.Background() |
|||
expiredInterval := 1 * time.Minute // Более короткий интервал истечения для тестирования GC
|
|||
runGCInterval := 10 * time.Second // Частый запуск GC для имитации работы
|
|||
|
|||
Init(ctx, expiredInterval, runGCInterval) |
|||
c := Cache() |
|||
|
|||
b.ResetTimer() |
|||
for i := 0; i < b.N; i++ { |
|||
var wg sync.WaitGroup |
|||
|
|||
// Чтение данных
|
|||
wg.Add(1) |
|||
go func() { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", rand.Intn(1000)) |
|||
_, _ = c.Get(key) |
|||
}() |
|||
|
|||
// Запись данных
|
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", i%1000) // Ограничение количества уникальных ключей для имитации повторных записей
|
|||
_, _ = c.Upsert(key, func() (interface{}, error) { |
|||
return fmt.Sprintf("value%d", i), nil |
|||
}, time.Duration(rand.Intn(5)+1)*time.Minute) // Рандомный интервал обновления
|
|||
}(i) |
|||
|
|||
// Обновление данных
|
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", rand.Intn(1000)) |
|||
_, _ = c.Upsert(key, func() (interface{}, error) { |
|||
return fmt.Sprintf("newValue%d", i), nil |
|||
}, time.Duration(rand.Intn(5)+1)*time.Minute) |
|||
}(i) |
|||
|
|||
// Удаление данных
|
|||
if i%10 == 0 { // Не на каждой итерации, чтобы не очищать все сразу
|
|||
wg.Add(1) |
|||
go func(i int) { |
|||
defer wg.Done() |
|||
key := fmt.Sprintf("key%d", rand.Intn(1000)) |
|||
c.Delete(key) |
|||
}(i) |
|||
} |
|||
|
|||
wg.Wait() |
|||
} |
|||
} |
Loading…
Reference in new issue