Skip to content

Commit c420418

Browse files
authored
chore(benchmark): improve add task in queue performance (#72)
* test(benchmark): add queue performance check * fix: defer Signed-off-by: Bo-Yi Wu <[email protected]> * chore: add pointer Signed-off-by: Bo-Yi Wu <[email protected]> * chore: update json library Signed-off-by: Bo-Yi Wu <[email protected]>
1 parent b3dd500 commit c420418

File tree

8 files changed

+62
-37
lines changed

8 files changed

+62
-37
lines changed

Diff for: .github/workflows/go.yml

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
- name: Run Tests
5959
run: |
6060
go test -v -covermode=atomic -coverprofile=coverage.out
61+
go test -v -run=^$ -benchmem -bench .
6162
6263
- name: Upload coverage to Codecov
6364
uses: codecov/codecov-action@v3

Diff for: consumer.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package queue
22

33
import (
44
"context"
5-
"encoding/json"
65
"errors"
76
"sync"
87
"sync/atomic"
98
"time"
109

10+
"github.com/goccy/go-json"
1111
"github.com/golang-queue/queue/core"
1212
)
1313

@@ -26,7 +26,7 @@ type Consumer struct {
2626
stopFlag int32
2727
}
2828

29-
func (s *Consumer) handle(job Job) error {
29+
func (s *Consumer) handle(job *Job) error {
3030
// create channel with buffer size 1 to avoid goroutine leak
3131
done := make(chan error, 1)
3232
panicChan := make(chan interface{}, 1)
@@ -79,13 +79,11 @@ func (s *Consumer) handle(job Job) error {
7979

8080
// Run to execute new task
8181
func (s *Consumer) Run(task core.QueuedMessage) error {
82-
var data Job
83-
_ = json.Unmarshal(task.Bytes(), &data)
84-
if v, ok := task.(Job); ok {
85-
if v.Task != nil {
86-
data.Task = v.Task
87-
}
82+
data := task.(*Job)
83+
if data.Task == nil {
84+
_ = json.Unmarshal(task.Bytes(), data)
8885
}
86+
8987
if err := s.handle(data); err != nil {
9088
return err
9189
}

Diff for: consumer_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func TestGoroutinePanic(t *testing.T) {
207207
}
208208

209209
func TestHandleTimeout(t *testing.T) {
210-
job := Job{
210+
job := &Job{
211211
Timeout: 100 * time.Millisecond,
212212
Payload: []byte("foo"),
213213
}
@@ -222,7 +222,7 @@ func TestHandleTimeout(t *testing.T) {
222222
assert.Error(t, err)
223223
assert.Equal(t, context.DeadlineExceeded, err)
224224

225-
job = Job{
225+
job = &Job{
226226
Timeout: 150 * time.Millisecond,
227227
Payload: []byte("foo"),
228228
}
@@ -245,7 +245,7 @@ func TestHandleTimeout(t *testing.T) {
245245
}
246246

247247
func TestJobComplete(t *testing.T) {
248-
job := Job{
248+
job := &Job{
249249
Timeout: 100 * time.Millisecond,
250250
Payload: []byte("foo"),
251251
}
@@ -259,7 +259,7 @@ func TestJobComplete(t *testing.T) {
259259
assert.Error(t, err)
260260
assert.Equal(t, errors.New("job completed"), err)
261261

262-
job = Job{
262+
job = &Job{
263263
Timeout: 250 * time.Millisecond,
264264
Payload: []byte("foo"),
265265
}
@@ -282,7 +282,7 @@ func TestJobComplete(t *testing.T) {
282282
}
283283

284284
func TestTaskJobComplete(t *testing.T) {
285-
job := Job{
285+
job := &Job{
286286
Timeout: 100 * time.Millisecond,
287287
Task: func(ctx context.Context) error {
288288
return errors.New("job completed")
@@ -294,7 +294,7 @@ func TestTaskJobComplete(t *testing.T) {
294294
assert.Error(t, err)
295295
assert.Equal(t, errors.New("job completed"), err)
296296

297-
job = Job{
297+
job = &Job{
298298
Timeout: 250 * time.Millisecond,
299299
Task: func(ctx context.Context) error {
300300
return nil
@@ -311,7 +311,7 @@ func TestTaskJobComplete(t *testing.T) {
311311
assert.NoError(t, err)
312312

313313
// job timeout
314-
job = Job{
314+
job = &Job{
315315
Timeout: 50 * time.Millisecond,
316316
Task: func(ctx context.Context) error {
317317
time.Sleep(60 * time.Millisecond)

Diff for: go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ module github.com/golang-queue/queue
33
go 1.18
44

55
require (
6+
github.com/goccy/go-json v0.9.7
67
github.com/golang/mock v1.6.0
78
github.com/stretchr/testify v1.7.1
89
go.uber.org/goleak v1.1.12
910
)
1011

1112
require (
12-
github.com/davecgh/go-spew v1.1.0 // indirect
13+
github.com/davecgh/go-spew v1.1.1 // indirect
1314
github.com/pmezard/go-difflib v1.0.0 // indirect
1415
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
1516
)

Diff for: go.sum

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
21
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
5+
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
36
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
47
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
58
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=

Diff for: queue.go

+17-19
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package queue
22

33
import (
44
"context"
5-
"encoding/json"
65
"errors"
76
"sync"
87
"sync/atomic"
98
"time"
109

10+
"github.com/goccy/go-json"
1111
"github.com/golang-queue/queue/core"
1212
)
1313

@@ -47,13 +47,17 @@ type (
4747
)
4848

4949
// Bytes get string body
50-
func (j Job) Bytes() []byte {
50+
func (j *Job) Bytes() []byte {
51+
if j.Task != nil {
52+
return nil
53+
}
5154
return j.Payload
5255
}
5356

5457
// Encode for encoding the structure
55-
func (j Job) Encode() []byte {
58+
func (j *Job) Encode() []byte {
5659
b, _ := json.Marshal(j)
60+
5761
return b
5862
}
5963

@@ -97,11 +101,11 @@ func (q *Queue) Shutdown() {
97101
return
98102
}
99103

100-
if q.metric.BusyWorkers() > 0 {
101-
q.logger.Infof("shutdown all tasks: %d workers", q.metric.BusyWorkers())
102-
}
103-
104104
q.stopOnce.Do(func() {
105+
if q.metric.BusyWorkers() > 0 {
106+
q.logger.Infof("shutdown all tasks: %d workers", q.metric.BusyWorkers())
107+
}
108+
105109
if err := q.worker.Shutdown(); err != nil {
106110
q.logger.Error(err)
107111
}
@@ -155,13 +159,11 @@ func (q *Queue) handleQueue(timeout time.Duration, job core.QueuedMessage) error
155159
return ErrQueueShutdown
156160
}
157161

158-
data := Job{
159-
Timeout: timeout,
160-
Payload: job.Bytes(),
161-
}
162-
163-
if err := q.worker.Queue(Job{
164-
Payload: data.Encode(),
162+
if err := q.worker.Queue(&Job{
163+
Payload: (&Job{
164+
Timeout: timeout,
165+
Payload: job.Bytes(),
166+
}).Encode(),
165167
}); err != nil {
166168
return err
167169
}
@@ -186,13 +188,9 @@ func (q *Queue) handleQueueTask(timeout time.Duration, task TaskFunc) error {
186188
return ErrQueueShutdown
187189
}
188190

189-
data := Job{
191+
if err := q.worker.Queue(&Job{
190192
Timeout: timeout,
191-
}
192-
193-
if err := q.worker.Queue(Job{
194193
Task: task,
195-
Payload: data.Encode(),
196194
}); err != nil {
197195
return err
198196
}

Diff for: queue_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package queue
22

33
import (
4+
"context"
45
"testing"
56
"time"
67

@@ -140,3 +141,26 @@ func TestCloseQueueAfterShutdown(t *testing.T) {
140141
assert.Error(t, err)
141142
assert.Equal(t, ErrQueueShutdown, err)
142143
}
144+
145+
func BenchmarkQueueTask(b *testing.B) {
146+
b.ReportAllocs()
147+
q := NewPool(5)
148+
defer q.Release()
149+
for n := 0; n < b.N; n++ {
150+
_ = q.QueueTask(func(context.Context) error {
151+
return nil
152+
})
153+
}
154+
}
155+
156+
func BenchmarkQueue(b *testing.B) {
157+
b.ReportAllocs()
158+
m := &mockMessage{
159+
message: "foo",
160+
}
161+
q := NewPool(5)
162+
defer q.Release()
163+
for n := 0; n < b.N; n++ {
164+
_ = q.Queue(m)
165+
}
166+
}

Diff for: worker_task.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type taskWorker struct {
1515
}
1616

1717
func (w *taskWorker) Run(task core.QueuedMessage) error {
18-
if v, ok := task.(Job); ok {
18+
if v, ok := task.(*Job); ok {
1919
if v.Task != nil {
2020
_ = v.Task(context.Background())
2121
}

0 commit comments

Comments
 (0)