Skip to content

Commit 06a6c4e

Browse files
Merge pull request #19 from DarthPestilane/refactor/router-simplify
Refactor: router simplify
2 parents 87ff2f2 + 7c3ae36 commit 06a6c4e

File tree

9 files changed

+124
-438
lines changed

9 files changed

+124
-438
lines changed

README.md

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,20 @@ in [examples/tcp](./examples/tcp).
102102

103103
## Benchmark
104104

105-
- goversion: 1.15.15
106-
- goos: darwin
107-
- goarch: amd64
108-
109-
| Benchmark name | (1) | (2) | (3) | (4) | remark |
110-
| ----------------------- | ------ | ---------- | --------- | ------------ | ----------------------------- |
111-
| NoRoute-8 | 250000 | 4584 ns/op | 79 B/op | 2 allocs/op | |
112-
| NotFoundHandler-8 | 250000 | 5471 ns/op | 565 B/op | 6 allocs/op | |
113-
| OneHandler-8 | 250000 | 6250 ns/op | 352 B/op | 7 allocs/op | |
114-
| ManyHandlers-8 | 250000 | 6405 ns/op | 464 B/op | 11 allocs/op | |
115-
| OneRouteCtxGetSet-8 | 250000 | 6940 ns/op | 697 B/op | 11 allocs/op | |
116-
| OneRouteMessageGetSet-8 | 250000 | 5406 ns/op | 623 B/op | 9 allocs/op | |
117-
| OneRouteJsonCodec-8 | 250000 | 7582 ns/op | 1383 B/op | 21 allocs/op | built with `encoding/json` |
118-
| OneRouteJsonCodec-8 | 250000 | 8430 ns/op | 1410 B/op | 17 allocs/op | built with `json-jsoniter/go` |
119-
| OneRouteProtobufCodec-8 | 250000 | 6628 ns/op | 444 B/op | 8 allocs/op | |
120-
| OneRouteMsgpackCodec-8 | 250000 | 7491 ns/op | 661 B/op | 11 allocs/op | |
105+
```sh
106+
go test -bench=. -run=none -benchmem -benchtime=250000x
107+
goos: darwin
108+
goarch: amd64
109+
pkg: github.com/DarthPestilane/easytcp
110+
Benchmark_NoHandler-8 250000 4479 ns/op 86 B/op 2 allocs/op
111+
Benchmark_OneHandler-8 250000 4377 ns/op 85 B/op 2 allocs/op
112+
Benchmark_OneHandlerCtxGetSet-8 250000 4076 ns/op 363 B/op 4 allocs/op
113+
Benchmark_OneHandlerMessageGetSet-8 250000 4202 ns/op 396 B/op 5 allocs/op
114+
PASS
115+
ok github.com/DarthPestilane/easytcp 4.609s
116+
```
117+
118+
*since easytcp is built on the top of golang `net` library, the benchmark of networks does not make much sense.*
121119

122120
## Architecture
123121

benchmarks_test.go

Lines changed: 8 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package easytcp
22

33
import (
4-
"github.com/DarthPestilane/easytcp/internal/test_data/msgpack"
5-
"github.com/DarthPestilane/easytcp/internal/test_data/pb"
64
"github.com/DarthPestilane/easytcp/message"
75
"net"
86
"testing"
@@ -15,7 +13,7 @@ type mutedLogger struct{}
1513
func (m *mutedLogger) Errorf(_ string, _ ...interface{}) {}
1614
func (m *mutedLogger) Tracef(_ string, _ ...interface{}) {}
1715

18-
func Benchmark_NoRoute(b *testing.B) {
16+
func Benchmark_NoHandler(b *testing.B) {
1917
s := NewServer(&ServerOption{
2018
DoNotPrintRoutes: true,
2119
})
@@ -38,73 +36,13 @@ func Benchmark_NoRoute(b *testing.B) {
3836
}
3937
}
4038

41-
func Benchmark_NotFoundHandler(b *testing.B) {
42-
s := NewServer(&ServerOption{
43-
DoNotPrintRoutes: true,
44-
})
45-
s.NotFoundHandler(func(ctx *Context) error {
46-
return ctx.Response(0, []byte("not found"))
47-
})
48-
go s.Serve("127.0.0.1:0") // nolint
49-
defer s.Stop() // nolint
50-
51-
<-s.accepting
52-
53-
// client
54-
client, err := net.Dial("tcp", s.Listener.Addr().String())
55-
if err != nil {
56-
panic(err)
57-
}
58-
defer client.Close() // nolint
59-
60-
packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: []byte("ping")})
61-
beforeBench(b)
62-
for i := 0; i < b.N; i++ {
63-
_, _ = client.Write(packedMsg)
64-
}
65-
}
66-
6739
func Benchmark_OneHandler(b *testing.B) {
6840
s := NewServer(&ServerOption{
6941
DoNotPrintRoutes: true,
7042
})
7143
s.AddRoute(1, func(ctx *Context) error {
72-
return ctx.Response(2, []byte("pong"))
73-
})
74-
go s.Serve("127.0.0.1:0") // nolint
75-
defer s.Stop() // nolint
76-
77-
<-s.accepting
78-
79-
// client
80-
client, err := net.Dial("tcp", s.Listener.Addr().String())
81-
if err != nil {
82-
panic(err)
83-
}
84-
defer client.Close() // nolint
85-
86-
packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: []byte("ping")})
87-
beforeBench(b)
88-
for i := 0; i < b.N; i++ {
89-
_, _ = client.Write(packedMsg)
90-
}
91-
}
92-
93-
func Benchmark_ManyHandlers(b *testing.B) {
94-
s := NewServer(&ServerOption{
95-
DoNotPrintRoutes: true,
44+
return nil
9645
})
97-
98-
var m MiddlewareFunc = func(next HandlerFunc) HandlerFunc {
99-
return func(ctx *Context) error {
100-
return next(ctx)
101-
}
102-
}
103-
104-
s.AddRoute(1, func(ctx *Context) error {
105-
return ctx.Response(2, []byte("pong"))
106-
}, m, m)
107-
10846
go s.Serve("127.0.0.1:0") // nolint
10947
defer s.Stop() // nolint
11048

@@ -124,14 +62,14 @@ func Benchmark_ManyHandlers(b *testing.B) {
12462
}
12563
}
12664

127-
func Benchmark_OneRouteCtxGetSet(b *testing.B) {
65+
func Benchmark_OneHandlerCtxGetSet(b *testing.B) {
12866
s := NewServer(&ServerOption{
12967
DoNotPrintRoutes: true,
13068
})
13169
s.AddRoute(1, func(ctx *Context) error {
13270
ctx.Set("key", "value")
133-
v := ctx.MustGet("key").(string)
134-
return ctx.Response(2, []byte(v))
71+
_ = ctx.MustGet("key").(string)
72+
return nil
13573
})
13674
go s.Serve("127.0.0.1:0") // nolint
13775
defer s.Stop() // nolint
@@ -152,14 +90,14 @@ func Benchmark_OneRouteCtxGetSet(b *testing.B) {
15290
}
15391
}
15492

155-
func Benchmark_OneRouteMessageGetSet(b *testing.B) {
93+
func Benchmark_OneHandlerMessageGetSet(b *testing.B) {
15694
s := NewServer(&ServerOption{
15795
DoNotPrintRoutes: true,
15896
})
15997
s.AddRoute(1, func(ctx *Context) error {
16098
ctx.Message().Set("key", []byte("val"))
161-
v := ctx.Message().MustGet("key").([]byte)
162-
return ctx.Response(2, v)
99+
_ = ctx.Message().MustGet("key").([]byte)
100+
return nil
163101
})
164102
go s.Serve("127.0.0.1:0") // nolint
165103
defer s.Stop() // nolint
@@ -180,95 +118,6 @@ func Benchmark_OneRouteMessageGetSet(b *testing.B) {
180118
}
181119
}
182120

183-
func Benchmark_OneRouteJsonCodec(b *testing.B) {
184-
s := NewServer(&ServerOption{
185-
Codec: &JsonCodec{},
186-
DoNotPrintRoutes: true,
187-
})
188-
s.AddRoute(1, func(ctx *Context) error {
189-
req := make(map[string]string)
190-
ctx.MustBind(&req)
191-
return ctx.Response(2, map[string]string{"data": "pong"})
192-
})
193-
go s.Serve("127.0.0.1:0") // nolint
194-
defer s.Stop() // nolint
195-
196-
<-s.accepting
197-
198-
// client
199-
client, err := net.Dial("tcp", s.Listener.Addr().String())
200-
if err != nil {
201-
panic(err)
202-
}
203-
defer client.Close() // nolint
204-
205-
packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: []byte(`{"data": "ping"}`)})
206-
beforeBench(b)
207-
for i := 0; i < b.N; i++ {
208-
_, _ = client.Write(packedMsg)
209-
}
210-
}
211-
212-
func Benchmark_OneRouteProtobufCodec(b *testing.B) {
213-
s := NewServer(&ServerOption{
214-
Codec: &ProtobufCodec{},
215-
DoNotPrintRoutes: true,
216-
})
217-
s.AddRoute(1, func(ctx *Context) error {
218-
var req pb.Sample
219-
ctx.MustBind(&req)
220-
return ctx.Response(2, &pb.Sample{Foo: "test-resp", Bar: req.Bar + 1})
221-
})
222-
go s.Serve("127.0.0.1:0") // nolint
223-
defer s.Stop() // nolint
224-
225-
<-s.accepting
226-
227-
// client
228-
client, err := net.Dial("tcp", s.Listener.Addr().String())
229-
if err != nil {
230-
panic(err)
231-
}
232-
defer client.Close() // nolint
233-
234-
data, _ := s.Codec.Encode(&pb.Sample{Foo: "test", Bar: 1})
235-
packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: data})
236-
beforeBench(b)
237-
for i := 0; i < b.N; i++ {
238-
_, _ = client.Write(packedMsg)
239-
}
240-
}
241-
242-
func Benchmark_OneRouteMsgpackCodec(b *testing.B) {
243-
s := NewServer(&ServerOption{
244-
Codec: &MsgpackCodec{},
245-
DoNotPrintRoutes: true,
246-
})
247-
s.AddRoute(1, func(ctx *Context) error {
248-
var req msgpack.Sample
249-
ctx.MustBind(&req)
250-
return ctx.Response(2, &msgpack.Sample{Foo: "test-resp", Bar: req.Bar + 1})
251-
})
252-
go s.Serve("127.0.0.1:0") // nolint
253-
defer s.Stop() // nolint
254-
255-
<-s.accepting
256-
257-
// client
258-
client, err := net.Dial("tcp", s.Listener.Addr().String())
259-
if err != nil {
260-
panic(err)
261-
}
262-
defer client.Close() // nolint
263-
264-
data, _ := s.Codec.Encode(&msgpack.Sample{Foo: "test", Bar: 1})
265-
packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: data})
266-
beforeBench(b)
267-
for i := 0; i < b.N; i++ {
268-
_, _ = client.Write(packedMsg)
269-
}
270-
}
271-
272121
func beforeBench(b *testing.B) {
273122
Log = &mutedLogger{}
274123
b.ReportAllocs()

examples/tcp/simple/server/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ func main() {
2727
SocketWriteBufferSize: 1024 * 1024,
2828
ReadTimeout: time.Second * 3,
2929
WriteTimeout: time.Second * 3,
30-
ReqQueueSize: -1,
3130
RespQueueSize: -1,
3231
Packer: easytcp.NewDefaultPacker(),
3332
Codec: nil,

router.go

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,8 @@ import (
88
"runtime"
99
)
1010

11-
func newRouter(queueSize ...int) *Router {
12-
size := 0
13-
if len(queueSize) != 0 {
14-
if qs := queueSize[0]; qs > 0 {
15-
size = qs
16-
}
17-
}
11+
func newRouter() *Router {
1812
return &Router{
19-
reqQueue: make(chan *Context, size),
20-
stopped: make(chan struct{}),
2113
handlerMapper: make(map[interface{}]HandlerFunc),
2214
middlewaresMapper: make(map[interface{}][]MiddlewareFunc),
2315
}
@@ -39,8 +31,6 @@ type Router struct {
3931
globalMiddlewares []MiddlewareFunc
4032

4133
notFoundHandler HandlerFunc
42-
reqQueue chan *Context
43-
stopped chan struct{}
4434
}
4535

4636
// HandlerFunc is the function type for handlers.
@@ -60,42 +50,6 @@ var nilHandler HandlerFunc = func(ctx *Context) error {
6050
return nil
6151
}
6252

63-
// stop stops the router.
64-
func (r *Router) stop() {
65-
close(r.stopped)
66-
}
67-
68-
// consumeRequest fetches context from reqQueue, and handle it.
69-
func (r *Router) consumeRequest() {
70-
defer func() { Log.Tracef("router stopped") }()
71-
for {
72-
select {
73-
case <-r.stopped:
74-
close(r.reqQueue)
75-
return
76-
case ctx, ok := <-r.reqQueue:
77-
if !ok {
78-
return
79-
}
80-
select {
81-
case <-ctx.session.closed:
82-
continue
83-
default:
84-
}
85-
86-
go func() {
87-
if err := r.handleRequest(ctx); err != nil {
88-
Log.Errorf("router handle request err: %s", err)
89-
return
90-
}
91-
if err := ctx.session.SendResp(ctx); err != nil {
92-
Log.Errorf("router send resp err: %s", err)
93-
}
94-
}()
95-
}
96-
}
97-
}
98-
9953
// handleRequest walks ctx through middlewares and handler,
10054
// and returns response message entry.
10155
func (r *Router) handleRequest(ctx *Context) error {
@@ -124,13 +78,11 @@ func (r *Router) handleRequest(ctx *Context) error {
12478
// var wrapped HandlerFunc = m1(m2(m3(handle)))
12579
func (r *Router) wrapHandlers(handler HandlerFunc, middles []MiddlewareFunc) (wrapped HandlerFunc) {
12680
if handler == nil {
127-
if r.notFoundHandler != nil {
128-
handler = r.notFoundHandler
129-
} else {
130-
handler = nilHandler
131-
}
81+
handler = r.notFoundHandler
82+
}
83+
if handler == nil {
84+
handler = nilHandler
13285
}
133-
13486
wrapped = handler
13587
for i := len(middles) - 1; i >= 0; i-- {
13688
m := middles[i]

0 commit comments

Comments
 (0)