Skip to content

Commit 8838e47

Browse files
authored
Merge pull request #1
* 添加pubsub核心实现,包括Broker、Publisher、Subscriber组件及完整测试用例 * 优化基准测试并添加示例代码:重构基准测试用例,增加通道容量和超时场景测试,添加快速入门示例,更新README文档 * 优化README文档描述:精简核心特性说明,突出实时Pub/Sub场景应用,调整措辞更精准体现库的无状态特性 * 重构项目结构:将核心代码移至pubsub子目录,调整示例代码路径,更新导入路径引用
1 parent b1c8742 commit 8838e47

File tree

12 files changed

+1405
-9
lines changed

12 files changed

+1405
-9
lines changed

.gitignore

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@
1111
# Test binary, built with `go test -c`
1212
*.test
1313

14-
# Code coverage profiles and other test artifacts
14+
# Output of the go coverage tool, specifically when used with LiteIDE
1515
*.out
16-
coverage.*
17-
*.coverprofile
18-
profile.cov
1916

2017
# Dependency directories (remove the comment below to include it)
2118
# vendor/
@@ -26,7 +23,4 @@ go.work.sum
2623

2724
# env file
2825
.env
29-
30-
# Editor/IDE
31-
# .idea/
32-
# .vscode/
26+
.idea

README.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,123 @@
11
# go-pubsub
2-
A lightweight real-time Pub-Sub library for Go.
2+
3+
<img src="logo.png" width="128px" alt="logo">
4+
5+
Lightweight, real-time Pub/Sub for Go—perfect for transient data flows like live dashboards, game events, short-lived alerts, and real-time streaming-media packet fan-out. It’s pure fire-and-forget: zero persistence, no delivery guarantees, just ultra-fast one-way messaging.
6+
7+
---
8+
9+
## Installation
10+
11+
```bash
12+
go get github.com/F2077/go-pubsub
13+
```
14+
15+
## Quick Start
16+
17+
```go
18+
package main
19+
20+
import (
21+
"fmt"
22+
"github.com/F2077/go-pubsub/pubsub"
23+
"time"
24+
)
25+
26+
func main() {
27+
// 1. Create a broker (supports generics)
28+
broker, _ := pubsub.NewBroker[string]()
29+
30+
// 2. Create a publisher
31+
publisher := pubsub.NewPublisher[string](broker)
32+
33+
// 3. Create a subscriber
34+
subscriber := pubsub.NewSubscriber[string](broker)
35+
36+
// 4. Subscribe to a topic with buffer size and timeout
37+
sub, _ := subscriber.Subscribe("alerts",
38+
pubsub.WithChannelSize[string](pubsub.Medium), // Buffer 100 messages
39+
pubsub.WithTimeout[string](5*time.Second), // Auto-close if idle
40+
)
41+
defer func(sub *pubsub.Subscription[string]) {
42+
_ = sub.Close()
43+
}(sub)
44+
45+
// 5. Publish a message
46+
go func() {
47+
_ = publisher.Publish("alerts", "CPU over 90%!")
48+
}()
49+
50+
// 6. Listen for messages or timeouts
51+
select {
52+
case msg := <-sub.Ch:
53+
fmt.Println("Received:", msg) // Output: "CPU over 90%!"
54+
case err := <-sub.ErrCh:
55+
fmt.Println("Error:", err) // e.g., timeout
56+
}
57+
}
58+
59+
```
60+
61+
## Key Features
62+
63+
- 🚀 **Zero Persistence**: Messages vanish if channels are full or subscribers time out.
64+
- ⏱️ **Auto-Expiry**: Idle subscriptions close automatically (configurable timeout).
65+
- 🔒 **Concurrency-Safe**: Efficient locking for high concurrency.
66+
- 📦 **Capacity Control**: Set max subscriptions per broker (prevents memory leaks).
67+
- 📡 **Topic-Based**: Simple publish/subscribe with string topics.
68+
69+
## Advanced Configuration
70+
71+
### Custom Broker
72+
73+
```go
74+
broker, _ := pubsub.NewBroker[string](
75+
pubsub.WithCapacity(5000), // Max 5000 topics
76+
pubsub.WithLogger(customLogger), // Inject your logger
77+
pubsub.WithId("broker-1"), // Custom broker ID
78+
)
79+
```
80+
81+
### Subscriber Options
82+
83+
```go
84+
// Subscribe with custom settings
85+
sub, _ := subscriber.Subscribe("metrics",
86+
pubsub.WithChannelSize[string](pubsub.Huge), // 1000-message buffer
87+
pubsub.WithTimeout[string](10 * time.Second), // Timeout after 10s inactivity
88+
)
89+
```
90+
91+
## When to Use
92+
93+
- ✅ Real-time pub-sub
94+
- ✅ Low-latency gaming/live events
95+
-**Not for**: Persistent queues, guaranteed delivery.
96+
97+
## Performance Notes
98+
99+
- 🔥 **Fast fan-out**: Optimized for many subscribers per topic.
100+
- ⚠️ **No backpressure**: Full channels drop messages silently.
101+
102+
---
103+
104+
## Benchmark Results
105+
106+
_All benchmarks run on_ **goos: windows**, **goarch: amd64**, **pkg: github.com/F2077/go-pubsub**, **cpu: Intel(R) Core(TM) i7-10700F CPU @ 2.90GHz**
107+
108+
| Benchmark | Iterations | ns/op | B/op | allocs/op |
109+
|--------------------------------------------------|-----------:|----------------:|-----:|----------:|
110+
| BenchmarkPublishSingleSubscriber-16 | 5 188 107 | 233.0 ns/op | 96 | 2 |
111+
| BenchmarkMultipleSubscribers-16 | 143 594 | 8 089 ns/op | 96 | 2 |
112+
| BenchmarkMultiPublisherSingleSubscriber-16 | 259 663 | 4 732 ns/op | 776 | 21 |
113+
| BenchmarkMultiPublisherMultipleSubscribers-16 | 67 593 | 17 823 ns/op | 776 | 21 |
114+
| BenchmarkUltraLargeSubscribersSinglePublisher-16 | 471 | 2 846 125 ns/op | 96 | 2 |
115+
| BenchmarkPublishChannelSizes/Small-16 | 5 271 156 | 230.2 ns/op | 96 | 2 |
116+
| BenchmarkPublishChannelSizes/Medium-16 | 5 134 640 | 229.5 ns/op | 96 | 2 |
117+
| BenchmarkPublishChannelSizes/Large-16 | 5 238 266 | 231.8 ns/op | 96 | 2 |
118+
| BenchmarkPublishWithTimeout-16 | 1 345 124 | 861.1 ns/op | 507 | 7 |
119+
| BenchmarkHighLoadParallel-16 | 14 728 | 83 785 ns/op | 100 | 2 |
120+
121+
---
122+
123+
**Contributions welcome!** Report bugs or suggest features via issues.

cmd/quickstart/main.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/F2077/go-pubsub/pubsub"
6+
"time"
7+
)
8+
9+
func main() {
10+
// 1. Create a broker (supports generics)
11+
broker, _ := pubsub.NewBroker[string]()
12+
13+
// 2. Create a publisher
14+
publisher := pubsub.NewPublisher[string](broker)
15+
16+
// 3. Create a subscriber
17+
subscriber := pubsub.NewSubscriber[string](broker)
18+
19+
// 4. Subscribe to a topic with buffer size and timeout
20+
sub, _ := subscriber.Subscribe("alerts",
21+
pubsub.WithChannelSize[string](pubsub.Medium), // Buffer 100 messages
22+
pubsub.WithTimeout[string](5*time.Second), // Auto-close if idle
23+
)
24+
defer func(sub *pubsub.Subscription[string]) {
25+
_ = sub.Close()
26+
}(sub)
27+
28+
// 5. Publish a message
29+
go func() {
30+
_ = publisher.Publish("alerts", "CPU over 90%!")
31+
}()
32+
33+
// 6. Listen for messages or timeouts
34+
select {
35+
case msg := <-sub.Ch:
36+
fmt.Println("Received:", msg) // Output: "CPU over 90%!"
37+
case err := <-sub.ErrCh:
38+
fmt.Println("Error:", err) // e.g., timeout
39+
}
40+
}

go.mod

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module github.com/F2077/go-pubsub
2+
3+
go 1.21
4+
5+
require (
6+
github.com/google/uuid v1.6.0
7+
github.com/stretchr/testify v1.10.0
8+
)
9+
10+
require (
11+
github.com/davecgh/go-spew v1.1.1 // indirect
12+
github.com/pmezard/go-difflib v1.0.0 // indirect
13+
gopkg.in/yaml.v3 v3.0.1 // indirect
14+
)

go.sum

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
4+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
8+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
10+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
11+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
12+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

logo.png

236 KB
Loading

0 commit comments

Comments
 (0)