Go 中 sync.Pool 存储 *[]T vs []T 的性能对比研究

Go 中 sync.Pool 存储 *[]T vs []T 的性能对比研究

背景

之前提交了一个功能,维护者后将一部分代码优化成如此,印象中返回具体类型性能会更好,想验证为什么需要返回使用指针。

研究

直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package slices

import (
"sync"
"testing"
)

const appendN = 1000

var optPool = sync.Pool{
New: func() any {
ints := make([]int, 0, appendN)
return &ints
},
}

func BenchmarkAppendWithPool(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sl := optPool.Get().(*[]int)
for j := 0; j < appendN; j++ {
*sl = append(*sl, j)
}
*sl = (*sl)[:0]
optPool.Put(sl)
}
}

var optPool2 = sync.Pool{
New: func() any {
return make([]int, 0, appendN)
},
}

func BenchmarkAppendWithPool2(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sl := optPool2.Get().([]int)
for j := 0; j < appendN; j++ {
sl = append(sl, j)
}
sl = sl[:0]
optPool2.Put(sl)
}
}

基准测试结果:

阅读更多
AI:基于 Eino + DeepSeek 配合 RSS 实现的每日简报功能

AI:基于 Eino + DeepSeek 配合 RSS 实现的每日简报功能

功能说明

  • 支持日期、星期
  • 支持天气、温度、湿度
  • 支持新闻摘要

直接看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package daily

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"testing"
"time"

"github.com/cloudwego/eino-ext/components/model/ark"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
"github.com/mmcdole/gofeed"
"github.com/stretchr/testify/require"
)

var fp = gofeed.NewParser()

func createModel(t *testing.T) model.ChatModel {
deepseek, err := ark.NewChatModel(t.Context(), &ark.ChatModelConfig{
BaseURL: "https://ark.cn-beijing.volces.com/api/v3",
APIKey: "[key]", // 请填写你的 API Key
Model: "deepseek-v3-241226",
})
require.NoError(t, err)
return deepseek
}

func TestDailyReport(t *testing.T) {
chain := compose.NewChain[string, *schema.Message]().
AppendParallel(
compose.NewParallel().
AddLambda("weather", compose.InvokableLambda(func(ctx context.Context, input string) (string, error) {
return fetchWeather(t), nil
})).
AddGraph("news",
compose.NewChain[string, string]().
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (*gofeed.Feed, error) {
return fp.ParseURL(input)
})).
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input *gofeed.Feed) (string, error) {
var buffer bytes.Buffer
for i, item := range input.Items {
buffer.WriteString(fmt.Sprintf("%d. %s\n", i+1, item.Title))
}
return buffer.String(), nil
})),
),
).
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input map[string]any) (string, error) {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("今日日期: %s, %s\n\n", time.Now().Format(time.DateOnly), time.Now().Weekday()))
buffer.WriteString(fmt.Sprintf("今日天气: %s\n", input["weather"].(string)))
buffer.WriteString(fmt.Sprintf("今日新闻:\n%s\n", input["news"].(string)))

return buffer.String(), nil
})).
AppendGraph(
compose.NewChain[string, *schema.Message]().
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) ([]*schema.Message, error) {
return []*schema.Message{
schema.SystemMessage(`You are a highly professional news summarization expert, capable of categorizing and organizing the article materials I provide into a summary format, presented in a point-by-point manner. Ultimately, deliver it to me in plain text, without Markdown syntax, in Chinese, as today's news summary.
**Format as follows:**

今天是 2021 年 3 月 19 日,星期五。天气晴朗,气温 20 度。以下是今日新闻摘要:

1. 企业动态:

- 华为将于3月20日至21日举行中国合作伙伴大会2025。
- 模速空间、无问芯穹和上海仪电推出国内首个“算力生态超市”。

2. 科技行业:

- 最低调“六小虎”阶跃星辰开年首秀,Agent落地智能终端,印奇也参与。
- “AI服务商”阿里巴巴值得重估。

...
`),
schema.UserMessage("Here are the articles:\n\n" + input),
}, nil
})).AppendChatModel(createModel(t)),
)

r, err := chain.Compile(t.Context())
require.NoError(t, err)

message, err := r.Stream(t.Context(), "https://36kr.com/feed")
require.NoError(t, err)

for {
msg, err := message.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
}
require.NoError(t, err)
fmt.Print(msg.Content)
}
}

type weatherResult struct {
Status string `json:"status"`
Count string `json:"count"`
Info string `json:"info"`
InfoCode string `json:"infocode"`
Lives []struct {
Province string `json:"province"`
City string `json:"city"`
AdCode string `json:"adcode"`
Weather string `json:"weather"`
Temperature string `json:"temperature"`
WindDirection string `json:"winddirection"`
WindPower string `json:"windpower"`
Humidity string `json:"humidity"`
ReportTime string `json:"reporttime"`
TemperatureFloat string `json:"temperature_float"`
HumidityFloat string `json:"humidity_float"`
} `json:"lives"`
}

func fetchWeather(t *testing.T) string {
resp, err := http.Get("https://restapi.amap.com/v3/weather/weatherInfo?key=[key]&city=440300&extensions=base") // 此处使用的是高德 API(有免费额度),此处使用的是深圳天气,实际应用,可自定义城市编码,或者做个映射关系。附 API 地址:https://lbs.amap.com/api/webservice/guide/api/weatherinfo/#t1
require.NoError(t, err)
defer resp.Body.Close()

var res weatherResult
require.NoError(t, json.NewDecoder(resp.Body).Decode(&res))
require.Equal(t, "1", res.Status)

return fmt.Sprintf("天气: %s,气温: %s,湿度: %s", res.Lives[0].Weather, res.Lives[0].Temperature, res.Lives[0].Humidity)
}

阅读更多
用 Llama3.1 解决大模型的经典问题:9.9 和 9.11 谁大

用 Llama3.1 解决大模型的经典问题:9.9 和 9.11 谁大

AI 的回复

首先是 GPT-4 的回复:

1
2
3
4
5
6
7
8
9
10
9.11 比 9.9 大。

在比较两个数字时,我们从左到右逐位进行比较:

1. 比较整数部分:9 和 9 相等。
2. 比较小数部分:.11 和 .9。

在小数部分比较时,.11 可以分解为 0.11,而 .9 可以分解为 0.90。显然,0.11 < 0.90。

因此,9.11 比 9.9 大。
阅读更多
Go:一种很“新”的类型断言

Go:一种很“新”的类型断言

分享组件:go-kratos-ecosystem/components

注:该功能计划在 v2.11.0 版本中发布。PR

引言

我们在早期使用 Go 做类型断言的时候,大多是这么用:

1
2
3
4
5
6
var v interface{}
v = 10

if _, ok := v.(int); ok {
fmt.Println("v is int")
}

那现在,我们只需要这么用:

1
2
3
if IsType[int](v) {
fmt.Println("v is int")
}
阅读更多
关于 12306 售票的一些思考研究

关于 12306 售票的一些思考研究

声明:本内容不一定是官方实际应用情况,仅为个人思考研究的方案。

问题:

买过票的都知道,乘客可以选车次的某站到某站,那意味着这期间的站点,该座位是不可售的。

那么,12306 是如何计算这个座位的售票情况的呢?

阅读更多
【架构设计】Websocket 消息格式之系统事件

【架构设计】Websocket 消息格式之系统事件

封面来源网络,如有侵权,请联系删除。

命名规范

系统事件的命名以 socket: 为前缀,例如 socket:connect 事件。

事件列表

WSS 连接成功 socket:connected

  • 事件发送方:服务端

  • 事件信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "event": "socket:connected",
    "data": {
    "socket_id": "1ba1b6cb-0127-48f8-b5a5-9fd79a7c68a6", // socket 唯一ID
    "heart": {
    "interval": 30, // 心跳间隔,单位:秒(用户客户端发送心跳事件)
    "timeout": 25 // 心跳超时,单位:秒(用于客户端接收心跳事件)
    }
    }
    }
阅读更多
有度 Golang 版 SDK
PHP 代码风格检测/修复工具:Laravel Pint

RocketMQ 安装

此处基于 Macbook Pro 的安装演示

环境依赖

安装 JDK

阅读更多

SPM 淘宝-导购效果跟踪

摘录为主

什么是 SPM

SPM是淘宝社区电商业务(xTao)为外部合作伙伴(外站)提供的一套跟踪引导成交效果数据的解决方案。

下面是一个跟踪点击到宝贝详情页的引导成交效果数据的SPM示例:

http://detail.tmall.com/item.htm?id=3716461318&&spm= 2014.123456789.1.2

其中spm=2014.123456789.1.2 便是下文所说的SPM编码

SPM编码:用来跟踪页面模块位置的编码,标准spm编码由4段组成,采用a.b.c.d的格式(建议 全部使用数字),其中,

阅读更多

Hyperf:JSON-RPC 服务

Server 端

定义服务(示例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

declare(strict_types=1);

namespace App\JsonRpc;

use Hyperf\RpcServer\Annotation\RpcService;

/**
* 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性.
* @RpcService(name="TestsService", protocol="jsonrpc-http", server="jsonrpc-http")
*/
class TestsService
{
// 实现一个加法方法,这里简单的认为参数都是 int 类型
public function add(int $a, int $b): int
{
// 这里是服务方法的具体实现
return $a + $b;
}
}
阅读更多

LeetCode:链表中倒数第 k 个节点

题目

输入一个链表,输出该链表中倒数第 k 个节点。为了符合大多数人的习惯,本题从 1 开始计数,即链表的尾节点是倒数第 1 个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

阅读更多

LeetCode: 移动零

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

1
2
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
阅读更多

LeetCode:Excel 表列名称

题目

给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。

例如:

A -> 1
B -> 2
C -> 3

Z -> 26
AA -> 27
AB -> 28

阅读更多

LeetCode:全排列

题目

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

1
2
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
阅读更多

LeetCode:字符串压缩

题目

字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串 aabcccccaaa 会变为 a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。

示例1:

1
2
输入:"aabcccccaaa"
输出:"a2b1c5a3"
阅读更多

LeetCode:回文排列

题目

给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。

回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。

回文串不一定是字典当中的单词。

示例1:

1
2
输入:"tactcoa"
输出:true(排列有"tacocat"、"atcocta",等等)
阅读更多

LeetCode:URL化

题目

URL 化。编写一种方法,将字符串中的空格全部替换为 %20 。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。(注:用Java实现的话,请使用字符数组实现,以便直接在数组上操作。)

示例 1:

1
2
输入:"Mr John Smith    ", 13
输出:"Mr%20John%20Smith"
阅读更多

LeetCode:判定是否互为字符重排

题目

给定两个字符串 s1s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

示例 1:

1
2
输入: s1 = "abc", s2 = "bca"
输出: true
阅读更多

LeetCode:目标和

题目

给你一个整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

阅读更多