{"id":20662062,"url":"https://github.com/livexy/linq","last_synced_at":"2026-02-12T22:32:37.178Z","repository":{"id":64297662,"uuid":"565007836","full_name":"LiveXY/linq","owner":"LiveXY","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-19T02:43:45.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-26T22:11:14.640Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiveXY.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-12T03:40:12.000Z","updated_at":"2025-02-19T02:43:48.000Z","dependencies_parsed_at":"2025-01-17T12:24:25.983Z","dependency_job_id":"d4f1bab7-5d50-4add-8823-6bb178cffd9a","html_url":"https://github.com/LiveXY/linq","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveXY%2Flinq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveXY%2Flinq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveXY%2Flinq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveXY%2Flinq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiveXY","download_url":"https://codeload.github.com/LiveXY/linq/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248667910,"owners_count":21142551,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T19:12:47.199Z","updated_at":"2026-02-12T22:32:37.173Z","avatar_url":"https://github.com/LiveXY.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# High-performance generic LINQ in Go\n\n使用方法:\n```\ngo get github.com/LiveXY/linq\n```\n\n测试代码:\n```\npackage test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/livexy/linq\"\n)\n\ntype BMember struct {\n\tName string\n\tID   int64\n\tAge  int\n\tSex  int8\n}\ntype SMember struct {\n\tName string\n\tID   int64\n}\n\nvar members = []*BMember{\n\t{ID: 1, Name: \"张三\", Sex: 1, Age: 28},\n\t{ID: 2, Name: \"李四\", Sex: 2, Age: 28},\n\t{ID: 3, Name: \"王五\", Sex: 1, Age: 29},\n\t{ID: 4, Name: \"老六\", Sex: 2, Age: 29},\n}\n\nfunc TestSum(t *testing.T) {\n\tfmt.Printf(\"Sum Age: %+v \\n\", linq.From(members).SumIntBy(func(m *BMember) int { return m.Age }))\n\tfmt.Printf(\"Avg Age: %+v \\n\", linq.From(members).AvgIntBy(func(m *BMember) int { return m.Age }))\n\tfmt.Printf(\"Sum Age: %+v \\n\", linq.SumBy(linq.From(members), func(m *BMember) int { return m.Age }))\n\tfmt.Printf(\"Min Age: %+v \\n\", linq.MinBy(linq.From(members), func(m *BMember) int { return m.Age }))\n\tfmt.Printf(\"Max Age: %+v \\n\", linq.MaxBy(linq.From(members), func(m *BMember) int { return m.Age }))\n}\nfunc TestPage(t *testing.T) {\n\tpage, pageSize := 1, 3\n\tout1 := linq.From(members).Skip((page - 1) * pageSize).Take(pageSize).ToSlice()\n\tfor _, v := range out1 {\n\t\tfmt.Printf(\"%d %+v \\n\", page, v)\n\t}\n\tpage = 2\n\tout1 = linq.From(members).Page(page, pageSize).ToSlice()\n\tfor _, v := range out1 {\n\t\tfmt.Printf(\"%d %+v \\n\", page, v)\n\t}\n}\nfunc TestUnion(t *testing.T) {\n\tout := linq.From(members).Union(linq.From(members)).ToSlice()\n\tfor _, v := range out {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n}\n\nfunc TestOrder(t *testing.T) {\n\tquery := linq.From(members)\n\tquery = linq.OrderByDescending(query, func(m *BMember) int8 { return m.Sex })\n\tquery = linq.ThenBy(query, func(m *BMember) int { return m.Age })\n\tout4 := query.ToSlice()\n\tfor _, v := range out4 {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n}\n\nfunc TestFrom(t *testing.T) {\n\tout := linq.From(members).\n\t\tWhere(func(m *BMember) bool { return m.Age \u003c 29 }).\n\t\tWhere(func(m *BMember) bool { return m.Sex \u003c 29 }).\n\t\tToSlice()\n\tfor _, v := range out {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n\tout2 := linq.Select(\n\t\tlinq.From(out),\n\t\tfunc(m *BMember) *SMember { return \u0026SMember{ID: m.ID, Name: m.Name} },\n\t).ToSlice()\n\tfor _, v := range out2 {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n\tout3 := linq.GroupBy(\n\t\tlinq.From(members),\n\t\tfunc(m *BMember) int8 { return m.Sex },\n\t).ToSlice()\n\tfor _, v := range out3 {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n\tout4 := linq.GroupBySelect(\n\t\tlinq.From(members),\n\t\tfunc(m *BMember) int8 { return m.Sex },\n\t\tfunc(m *BMember) *BMember { return m },\n\t).ToSlice()\n\tfor _, v := range out4 {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n}\n\nfunc TestFilter(t *testing.T) {\n\tout2 := linq.Filter(\n\t\tlinq.From(members),\n\t\tfunc(m *BMember) (*SMember, bool) { return nil, false },\n\t).ToSlice()\n\tfor _, v := range out2 {\n\t\tfmt.Printf(\"%+v \\n\", v)\n\t}\n}\nfunc TestHasOrder(t *testing.T) {\n\tquery := linq.From(members).\n\t\tWhere(func(m *BMember) bool { return m.Age \u003c 29 }).\n\t\tWhere(func(m *BMember) bool { return m.Sex \u003c 29 })\n\tfmt.Printf(\"%+v \\n\", query.HasOrder())\n\tquery = linq.OrderByDescending(query, func(m *BMember) int8 { return m.Sex })\n\tfmt.Printf(\"%+v \\n\", query.HasOrder())\n}\n\nfunc TestFirst(t *testing.T) {\n\tfmt.Println(1, linq.From([]*BMember{}).Where(func(m *BMember) bool { return m.Age \u003c 29 }).DefaultIfEmpty(\u0026BMember{}).First())\n\tfmt.Println(2, linq.From([]*BMember{}).Where(func(m *BMember) bool { return m.Age \u003c 29 }).First())\n}\n\n```\n\n## 性能测试 (Performance Benchmark)\n\n基于 Apple M4 Pro (macOS/arm64) 的测试结果：\n\n| 测试场景 (Benchmark)   | 单次耗时 (ns/op) | 内存 (B/op) | 分配次数 (allocs/op) | 说明 |\n|-----------------------|-----------------|-------------|---------------------|------|\n| `FromString`          | **7,757**       | **56**      | **2**               | **零拷贝**字符串遍历，内存开销极低 |\n| `MinBy`               | 16,396          | 72          | 2                   | 流式处理，极低内存占用 |\n| `Where` (Filter)      | 26,303          | 128,352     | 19                  | 10,000 元素过滤 |\n| `Union`               | 38,573          | 90,648      | 21                  | 集合合并优化 |\n| `FromSlice`           | 45,833          | 357,697     | 21                  | 10,000 元素切片转换 |\n| `Select` (Map)        | 45,879          | 357,729     | 22                  | 10,000 元素映射 |\n| `Sort`                | 10,760          | 50,712      | 32                  | 1,000 元素排序 |\n| `GroupBy`             | 146,036         | 224,864     | 831                 | 10,000 元素确定性分组 |\n\n\u003e **Highlight**: `FromString` 采用了 UTF-8 解码优化，避免了全量 `rune` 数组转换，性能与内存表现卓越。\n\n测试命令: `go test -bench=. -benchmem`\n\n## 高并发场景优化 (High Concurrency Optimization)\n\n本库针对高并发场景进行了深度优化，提供以下特性：\n\n### 🚀 核心特性\n\n#### 1. BufferPool - 切片复用，降低 GC 压力\n```go\npool := linq.NewBufferPool[int]()\n\n// 获取复用的 buffer\nbuf := pool.Get(1000)\nresult := linq.From(data).Where(filter).AppendTo(buf)\n\n// 使用完后归还\ndefer pool.Put(result[:0])\n```\n\n#### 2. Comparable 类型优化 - 避免装箱，性能提升 42%\n```go\n// ✅ 推荐：使用优化版本\nresult := linq.DistinctComparable(linq.From(numbers)).ToSlice()\n\n// ❌ 避免：会产生装箱开销\nresult := linq.From(numbers).Distinct().ToSlice()\n```\n\n**性能对比**（10,000 元素）：\n- `DistinctComparable`: 68,812 ns/op, 99,768 B/op, 37 allocs/op\n- `Distinct`: 119,023 ns/op, 140,280 B/op, 781 allocs/op\n- **提升**: 42% 更快，分配次数减少 95%\n\n#### 3. 并发处理 - 内置 Panic 恢复\n```go\n// ForEachParallel - 并发执行，自动恢复 panic\nlinq.From(items).ForEachParallel(10, func(item Item) {\n    processItem(item) // 即使 panic 也不会影响其他 worker\n})\n\n// SelectAsync - 并发转换，支持提前退出\nresult := linq.SelectAsync(query, 5, expensiveTransform).\n    Take(100).\n    ToSlice()\n```\n\n### ⚠️ 重要说明\n\n- **Goroutine 安全**: 所有并发方法都已修复 goroutine 泄漏问题\n- **Panic 隔离**: `ForEachParallel` 和 `SelectAsync` 内置 panic 恢复机制\n- **内存优化**: 使用 `BufferPool` 可降低 60% 的 GC 压力\n\n详细优化报告请查看 [CONCURRENT_OPTIMIZATION.md](./CONCURRENT_OPTIMIZATION.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivexy%2Flinq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flivexy%2Flinq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivexy%2Flinq/lists"}