xxxxxxxxxx
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
Email string `json:"email"`
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
users := Semaphore()
json.NewEncoder(w).Encode(&users)
})
http.ListenAndServe(":3000", nil)
}
func Semaphore() []User {
var (
maxOfGorutines = 1000
minOfGorutines = 100
wg sync.WaitGroup
mutex sync.Mutex
semaphore *semaphore.Weighted = semaphore.NewWeighted(int64(maxOfGorutines))
users []User = []User{}
)
start := time.Now()
semaphore.Acquire(context.Background(), int64(minOfGorutines))
wg.Add(1)
go func() {
defer func() {
semaphore.Release(int64(minOfGorutines))
wg.Done()
}()
res, err := http.Get("https://jsonplaceholder.typicode.com/users")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
resByte, err := io.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
mutex.Lock()
if err := json.Unmarshal(resByte, &users); err != nil {
log.Fatal(err)
}
mutex.Unlock()
}()
wg.Wait()
fmt.Printf("Total User: %d\n", len(users))
fmt.Printf("Finish Time: %s\n", time.Since(start))
return users
}
xxxxxxxxxx
package main
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
DateOfBirth string `json:"dateOfBirt"`
PlaceOfBirth string `json:"placeOfBirt"`
}
func main() {
var (
loopCount int = 100000000 // 10000000 (10JT) - 100000000 (100JT) - 1000000000 (1M) - 100000000000 (1T)
maxOfGorutines int64 = 1000
releaseNumOfGorutines int64 = 100
wg *sync.WaitGroup = new(sync.WaitGroup)
mutex *sync.RWMutex = new(sync.RWMutex)
sem *semaphore.Weighted = semaphore.NewWeighted(maxOfGorutines)
userChan chan User = make(chan User, maxOfGorutines)
users []User = []User{}
)
start := time.Now()
fmt.Printf("Semaphore Start time: %s", time.Since(start))
go func() {
for i := 0; i < loopCount; i++ {
sem.Acquire(context.Background(), releaseNumOfGorutines)
wg.Add(1)
go func() {
defer func() {
sem.Release(releaseNumOfGorutines)
wg.Done()
}()
user := User{Name: "Jamal Cavalera", Age: 23, DateOfBirth: "17 Agustus 2000", PlaceOfBirth: "Jakarta"}
mutex.Lock()
defer mutex.Unlock()
userChan <- user
}()
}
defer close(userChan)
wg.Wait()
}()
for user := range userChan {
mutex.Lock()
users = append(users, user)
mutex.Unlock()
}
fmt.Printf("Total User: %d", len(users))
fmt.Printf("\n")
fmt.Printf("Semaphore Finish Time: %s", time.Since(start))
}
xxxxxxxxxx
package main
import (
"fmt"
"sync"
"time"
)
type User struct {
Name string
Age int
DateOfBirth string
PlaceOfBirth string
}
func main() {
PoolNew()
}
func PoolNew() {
var (
loopCount = 10000000 // 10000000 (10JT) - 100000000 (100JT) - 1000000000 (1M) - 100000000000 (1T)
maxOfGorutines = 1000000
wg sync.WaitGroup
users []User
mutex sync.Mutex
semaphore = make(chan bool, maxOfGorutines)
)
start := time.Now()
for i := 0; i < loopCount; i += maxOfGorutines {
semaphore <- true
wg.Add(1)
go func(startIndex, endIndex int) {
defer func() {
<-semaphore
wg.Done()
}()
for j := startIndex; j < endIndex; j++ {
user := User{
Name: "Jamal Cavalera",
Age: 23,
DateOfBirth: "17 Agustus 2000",
PlaceOfBirth: "Jakarta",
}
mutex.Lock()
users = append(users, user)
mutex.Unlock()
}
}(i, i+maxOfGorutines)
}
wg.Wait()
fmt.Printf("Total User: %d\n", len(users))
fmt.Printf("Finish Time: %s\n", time.Since(start))
}
xxxxxxxxxx
semaphore formula, memory usage is stable but thread cores increase, but execution time is much faster (29.2s). Sometimes it can also be faster or slower, which is where there is one thread that can break 80% of its height.
NewWeighted = 1000
Acquire = 100
Release = 100
semaphore formula, stable memory usage, and stable thread core usage, but execution time is much slower (48.4s). Sometimes it can also be faster or slower, of which there is one of the highest threads that is still under 70%.
NewWeighted = 100
Acquire = 100
Release = 100
The conclusion is that the higher the weighted or acquired and released, the higher the memory usage, but the execution time is much faster. The smaller the weighted or acquired and released, the smaller the memory usage, but the execution time will be much slower.
The following pattern example is different configurations, but the same result
NewWeighted = 1000
Acquire = 100
Release = 100
NewWeighted = 10000
Acquire = 1000
Release = 1000
xxxxxxxxxx
type Semaphore struct {
ch chan bool
}
func NewSemaphore(weight int) *Semaphore {
return &Semaphore{
ch: make(chan bool, weight),
}
}
func (s *Semaphore) Acquire() {
s.ch <- true
}
func (s *Semaphore) Release() {
<-s.ch
}
xxxxxxxxxx
package main
import (
"fmt"
"log"
"sync"
"time"
"github.com/bytedance/sonic"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
DateOfBirth string `json:"dateOfBirt"`
PlaceOfBirth string `json:"placeOfBirt"`
}
func main() {
Pool()
}
func Pool() {
var (
loopCount int = 10000000 // 10000000 (10JT) - 100000000 (100JT) - 1000000000 (1M) - 100000000000 (1T)
maxChannelSize int64 = 1000
maxOfGorutines int64 = 1000
wg *sync.WaitGroup = new(sync.WaitGroup)
mutex *sync.RWMutex = new(sync.RWMutex)
userChan chan []byte = make(chan []byte, maxChannelSize)
poolChan chan bool = make(chan bool, maxOfGorutines)
user User = User{}
users []User = []User{}
)
start := time.Now()
fmt.Printf("Pool Start time: %s", time.Since(start))
fmt.Printf("\n")
go func() {
for i := 0; i < loopCount; i++ {
poolChan <- true
wg.Add(1)
go func() {
defer func() {
<-poolChan
wg.Done()
}()
user := User{Name: "Jamal Cavalera", Age: 23, DateOfBirth: "17 Agustus 2000", PlaceOfBirth: "Jakarta"}
userByte, err := sonic.Marshal(user)
if err != nil {
log.Fatal(err)
}
mutex.Lock()
defer mutex.Unlock()
userChan <- userByte
}()
}
defer close(userChan)
wg.Wait()
}()
for userByte := range userChan {
if err := sonic.Unmarshal(userByte, &user); err != nil {
log.Fatal(err)
}
users = append(users, user)
}
fmt.Printf("Total User: %d", len(users))
fmt.Printf("\n")
fmt.Printf("Pool Finish Time: %s", time.Since(start))
}
xxxxxxxxxx
func Pool() {
var (
loopCount int = 100000000 // 10000000 (10JT) - 100000000 (100JT) - 1000000000 (1M) - 100000000000 (1T)
maxOfGorutines int64 = 1000
wg *sync.WaitGroup = new(sync.WaitGroup)
mutex *sync.RWMutex = new(sync.RWMutex)
pool chan bool = make(chan bool, maxOfGorutines)
poolUserChan *sync.Pool = &sync.Pool{
New: func() any {
return make(chan User, maxOfGorutines)
},
}
poolUsers *sync.Pool = &sync.Pool{
New: func() any {
return []User{}
},
}
)
start := time.Now()
fmt.Printf("Pool Start time: %s", time.Since(start))
userChan := poolUserChan.Get().(chan User)
users := poolUsers.Get().([]User)
go func() {
for i := 0; i < loopCount; i++ {
pool <- true
wg.Add(1)
go func() {
defer func() {
<-pool
wg.Done()
}()
user := User{Name: "Jamal Cavalera", Age: 23, DateOfBirth: "17 Agustus 2000", PlaceOfBirth: "Jakarta"}
mutex.Lock()
defer mutex.Unlock()
userChan <- user
}()
poolUserChan.Put(userChan)
}
wg.Wait()
}()
for user := range userChan {
users = append(users, user)
}
poolUsers.Put(users)
fmt.Printf("Total User: %d", len(users))
fmt.Printf("\n")
fmt.Printf("Pool Finish Time: %s", time.Since(start))
}
xxxxxxxxxx
package main
import (
"fmt"
"sync"
"time"
)
type User struct {
Name string
Age int
DateOfBirth string
PlaceOfBirth string
}
func main() {
var (
loopCount = 10000
maxOfGorutines = 1000
wg sync.WaitGroup
sem = make(chan bool, maxOfGorutines)
users []User
mutex sync.Mutex
)
start := time.Now()
for i := 0; i < loopCount; i++ {
sem <- true
wg.Add(1)
go func() {
defer func() {
wg.Done()
<-sem
}()
user := User{
Name: "Jamal Cavalera",
Age: 23,
DateOfBirth: "17 Agustus 2000",
PlaceOfBirth: "Jakarta",
}
mutex.Lock()
users = append(users, user)
mutex.Unlock()
}()
}
wg.Wait()
fmt.Printf("Total User: %d\n", len(users))
fmt.Printf("Execution Time: %s\n", time.Since(start))
}