Skip to content

Commit f4a306a

Browse files
committed
add docs
1 parent d2702d1 commit f4a306a

File tree

6 files changed

+180
-21
lines changed

6 files changed

+180
-21
lines changed

README.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Itogami
2+
3+
> The best goroutine pool till date
4+
5+
Saves a lot of memory and is the fastest among all existing golang threadpool implementations
6+
7+
Benchmarks to support the above claims [here](#benchmarks)
8+
9+
## Installation
10+
11+
You need Golang [1.18.x](https://go.dev/dl/) or above since this package uses generics
12+
13+
```bash
14+
$ go get github.com/alphadose/[email protected]
15+
```
16+
17+
## Usage
18+
19+
```go
20+
package main
21+
22+
import (
23+
"fmt"
24+
"sync"
25+
"sync/atomic"
26+
"time"
27+
28+
"github.com/alphadose/itogami"
29+
)
30+
31+
const runTimes uint32 = 1000
32+
33+
var sum uint32
34+
35+
func myFunc(i uint32) {
36+
atomic.AddUint32(&sum, i)
37+
fmt.Printf("run with %d\n", i)
38+
}
39+
40+
func demoFunc() {
41+
time.Sleep(10 * time.Millisecond)
42+
println("Hello World")
43+
}
44+
45+
func examplePool() {
46+
var wg sync.WaitGroup
47+
// Use the common pool
48+
pool := itogami.NewPool(10)
49+
50+
syncCalculateSum := func() {
51+
demoFunc()
52+
wg.Done()
53+
}
54+
for i := uint32(0); i < runTimes; i++ {
55+
wg.Add(1)
56+
// Submit task to the pool
57+
pool.Submit(syncCalculateSum)
58+
}
59+
wg.Wait()
60+
println("finished all tasks")
61+
}
62+
63+
func examplePoolWithFunc() {
64+
var wg sync.WaitGroup
65+
// Use the pool with a pre-defined function
66+
pool := itogami.NewPoolWithFunc(10, func(i uint32) {
67+
myFunc(i)
68+
wg.Done()
69+
})
70+
for i := uint32(0); i < runTimes; i++ {
71+
wg.Add(1)
72+
// Invoke the function with a value
73+
pool.Invoke(i)
74+
}
75+
wg.Wait()
76+
fmt.Printf("finish all tasks, result is %d\n", sum)
77+
}
78+
79+
func main() {
80+
examplePool()
81+
examplePoolWithFunc()
82+
}
83+
```
84+
85+
## Benchmarks
86+
87+
Benchmarking was performed against existing golang threadpool implementations [Ants](https://github.com/panjf2000/ants) and [Gamma-Zero-Worker-Pool](https://github.com/gammazero/workerpool) and unlimited goroutines
88+
89+
Thread pool size -> 50k
90+
91+
CPU -> M1, arm64, 8 cores, 3.2 GHz
92+
93+
OS -> darwin
94+
95+
Results were computed from [benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat) of 30 cases
96+
```
97+
name time/op
98+
UnlimitedGoroutines-8 291ms ± 2%
99+
AntsPool-8 512ms ± 6%
100+
GammaZeroPool-8 713ms ±10%
101+
ItogamiPool-8 319ms ± 1%
102+
103+
name alloc/op
104+
UnlimitedGoroutines-8 96.2MB ± 0%
105+
AntsPool-8 21.8MB ± 9%
106+
GammaZeroPool-8 18.8MB ± 1%
107+
ItogamiPool-8 25.8MB ± 3%
108+
109+
name allocs/op
110+
UnlimitedGoroutines-8 2.00M ± 0%
111+
AntsPool-8 1.09M ± 3%
112+
GammaZeroPool-8 1.05M ± 0%
113+
ItogamiPool-8 1.05M ± 0%
114+
```
115+
116+
The following conclusions can be drawn from the above results:-
117+
118+
1. Itogami is the fastest among all threadpool implementations and slower only than unlimited goroutines
119+
2. Itogami has the least `allocs/op` and hence the memory usage scales really well with high load
120+
3. The memory used per operation is in the acceptable range of other threadpools and drastically lower than unlimited goroutines
121+
4. The tolerance (± %) for Itogami is quite low for all 3 metrics indicating that the algorithm is quite stable overall

benchmarks/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ import "time"
55
const (
66
RunTimes = 1e6
77
BenchParam = 10
8-
PoolSize = 2e5
8+
PoolSize = 5e4
99
DefaultExpiredTime = 10 * time.Second
1010
)

benchmarks/general_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/alphadose/itogami"
9+
"github.com/gammazero/workerpool"
910
"github.com/panjf2000/ants/v2"
1011
)
1112

@@ -51,6 +52,25 @@ func BenchmarkAntsPool(b *testing.B) {
5152
b.StopTimer()
5253
}
5354

55+
func BenchmarkGammaZeroPool(b *testing.B) {
56+
var wg sync.WaitGroup
57+
p := workerpool.New(PoolSize)
58+
59+
b.ResetTimer()
60+
b.StartTimer()
61+
for i := 0; i < b.N; i++ {
62+
wg.Add(RunTimes)
63+
for j := 0; j < RunTimes; j++ {
64+
p.Submit(func() {
65+
demoFunc()
66+
wg.Done()
67+
})
68+
}
69+
wg.Wait()
70+
}
71+
b.StopTimer()
72+
}
73+
5474
func BenchmarkItogamiPool(b *testing.B) {
5575
var wg sync.WaitGroup
5676
p := itogami.NewPool(PoolSize)

examples/main.go

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,55 @@ import (
99
"github.com/alphadose/itogami"
1010
)
1111

12-
var sum int32
12+
const runTimes uint32 = 1000
1313

14-
func myFunc(i int32) {
15-
atomic.AddInt32(&sum, i)
14+
var sum uint32
15+
16+
func myFunc(i uint32) {
17+
atomic.AddUint32(&sum, i)
1618
fmt.Printf("run with %d\n", i)
1719
}
1820

1921
func demoFunc() {
2022
time.Sleep(10 * time.Millisecond)
21-
fmt.Println("Hello World!")
23+
println("Hello World")
2224
}
2325

24-
func main() {
25-
runTimes := int32(1000)
26-
pool := itogami.NewPool(10)
27-
// Use the common pool.
26+
func examplePool() {
2827
var wg sync.WaitGroup
28+
// Use the common pool
29+
pool := itogami.NewPool(10)
30+
2931
syncCalculateSum := func() {
3032
demoFunc()
3133
wg.Done()
3234
}
33-
for i := int32(0); i < runTimes; i++ {
35+
for i := uint32(0); i < runTimes; i++ {
3436
wg.Add(1)
37+
// Submit task to the pool
3538
pool.Submit(syncCalculateSum)
3639
}
3740
wg.Wait()
38-
fmt.Printf("finish all tasks.\n")
41+
println("finished all tasks")
42+
}
3943

40-
// Use the pool with a function,
41-
// set 10 to the capacity of goroutine pool and 1 second for expired duration.
42-
p := itogami.NewPoolWithFunc(10, func(i int32) {
44+
func examplePoolWithFunc() {
45+
var wg sync.WaitGroup
46+
// Use the pool with a pre-defined function
47+
pool := itogami.NewPoolWithFunc(10, func(i uint32) {
4348
myFunc(i)
4449
wg.Done()
4550
})
46-
// Submit tasks one by one.
47-
for i := int32(0); i < runTimes; i++ {
51+
for i := uint32(0); i < runTimes; i++ {
4852
wg.Add(1)
49-
p.Invoke(i)
53+
// Invoke the function with a value
54+
pool.Invoke(i)
5055
}
5156
wg.Wait()
5257
fmt.Printf("finish all tasks, result is %d\n", sum)
5358
}
59+
60+
func main() {
61+
examplePool()
62+
examplePoolWithFunc()
63+
}

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module github.com/alphadose/itogami
33
go 1.18
44

55
require (
6-
github.com/panjf2000/ants v1.3.0 // indirect
7-
github.com/panjf2000/ants/v2 v2.5.0 // indirect
6+
github.com/gammazero/workerpool v1.1.2
7+
github.com/panjf2000/ants/v2 v2.5.0
88
)
9+
10+
require github.com/gammazero/deque v0.1.0 // indirect

go.sum

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M=
2-
github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY=
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/gammazero/deque v0.1.0 h1:f9LnNmq66VDeuAlSAapemq/U7hJ2jpIWa4c09q8Dlik=
3+
github.com/gammazero/deque v0.1.0/go.mod h1:KQw7vFau1hHuM8xmI9RbgKFbAsQFWmBpqQ2KenFLk6M=
4+
github.com/gammazero/workerpool v1.1.2 h1:vuioDQbgrz4HoaCi2q1HLlOXdpbap5AET7xu5/qj87g=
5+
github.com/gammazero/workerpool v1.1.2/go.mod h1:UelbXcO0zCIGFcufcirHhq2/xtLXJdQ29qZNlXG9OjQ=
36
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
47
github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
8+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
9+
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
10+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=

0 commit comments

Comments
 (0)