Skip to content

Commit 8707eec

Browse files
committed
ruipingbaiyanlangoldboss
1 parent 47d78b9 commit 8707eec

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@
3737
- 自定义模板 (待认领)
3838
- TODO: 更多章节
3939

40+
## 赞助名单
41+
42+
感谢以下小彭友的赞助!
43+
44+
[![Thanks list](pic/thanks.png)](https://afdian.net/a/archibate)
45+
46+
小彭老师的大典是免费下载的,不用赞助也可以查看哦。
47+
48+
> [!NOTE]
49+
> 但是小彭老师遭到“白眼狼”脑板开除,目前处于失业状态。不得不寻求各位小彭友的赞助,保障小彭老师的基本生命体征。
50+
51+
如果你觉得本书对你有所帮助,可以通过 [爱发电](https://afdian.net/a/archibate) 赞助小彭老师,以便小彭老师有更多的精力继续编写和维护本书。
52+
53+
> [!TIP]
54+
> 每有一位小彭友赞助 `26.90`,小彭老师一天的食品安全就有了着落。
55+
56+
<a href="https://afdian.net/a/archibate"><img src="https://142857.red/afdian-qrcode.jpg?y" alt="https://afdian.net/a/archibate" width="400px"/></a>
57+
58+
> [!TIP]
59+
> 如果你也处于失业状态,就不用勉强赞助了……也可以先给小彭老师点一颗⭐Star⭐表示心意。
60+
4061
## Typst 真好用,家人们
4162

4263
本书使用 [Typst 语言](https://github.com/typst/typst) 书写,类似于 LaTeX 或 Markdown。和 Markdown 相比,Typst 的排版功能更加丰富。和 LaTeX 相比,Typst 更加轻量级,语法简单明了。最重要的是,Typst 支持宏编程,可以在文本中书写代码,实现批量生成结构化的文本。

cppguidebook.typ

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,24 +1385,44 @@ int generic_sum<max>(std::vector<int> const &v) {
13851385

13861386
为三种不同的 op 参数分别定做三份。虽然增加了编译时间,膨胀了生成的二进制体积;但生成的机器码是分别针对每种特例一对一深度优化的,更高效。
13871387

1388-
#story[例如矩阵乘法(gemm)的最优算法,对于不同的矩阵大小和形状是不同的。著名的线性代数库 CUBLAS 和 MKL 中,会自动根据用户输入的矩阵形状,选取最优的算法。也就是说,CUBLAS 库里其实存着适合各种矩阵大小排列组合的算法代码(以 fatbin 格式存储在二进制中)。当调用矩阵乘法时,自动查到最适合的一版来调用给你。类似 gemm,还有 gemv、spmv……所有的 API 都经历了这样的“编译期”暴力排列组合,只为“运行时”释放最大性能!这也导致了生成的 cublas.dll 文件来到了恐怖的 20 MB 左右,而我们称之为高效。]
1388+
#story[例如矩阵乘法(gemm)的最优算法,对于不同的矩阵大小和形状是不同的。著名的线性代数库 CUBLAS 和 MKL 中,会自动根据用户输入的矩阵形状,选取最优的算法。也就是说,CUBLAS 库里其实存着适合各种矩阵大小排列组合的算法代码(以 fatbin 格式存储在二进制中)。当调用矩阵乘法时,自动查到最适合的一版来调用给你。类似 gemm,还有 gemv、spmv……所有的矩阵运算 API 都经历了这样的“编译期”暴力排列组合,只为“运行时”释放最大性能!这也导致编译好的 cublas.dll 文件来到了恐怖的 20 MB 左右,而我们称之为高效。]
13891389

13901390
=== 函数对象也可在 function 容器中动态分发
13911391

1392+
`std::function<int(int, int)>`
1393+
1394+
```cpp
1395+
int generic_sum(std::vector<int> const &v,
1396+
std::function<int(int, int)> op) {
1397+
int ret = v[0];
1398+
for (int i = 1; i < v.size(); ++i) {
1399+
ret = op(ret, v[i]); // 写起来和模板传参时一样无感
1400+
}
1401+
// 无需指针,无需 delete,function 能自动管理函数对象生命周期
1402+
return ret;
1403+
}
1404+
```
1405+
13921406
函数式编程,能在静态与动态之间轻松切换,高性能与灵活性任君选择。
13931407

1394-
可以在需要性能的瓶颈代码中用模板传参,编译期静态分发,多次量身定做,提高运行时性能。
1408+
可以在需要性能的*瓶颈代码*中用模板传参,编译期静态分发,多次量身定做,提高运行时性能。
1409+
1410+
/ 瓶颈代码: 往往一个程序 80% 的时间花在 20% 的代码上。这 20% 是在程序中频繁执行的、计算量大的、或者调用特别耗时的函数。针对这部分瓶颈代码优化即可,而剩余的 80% 打酱油代码,大可以怎么方便怎么写。
13951411

13961412
可以在性能无关紧要的顶层业务逻辑中用 function 容器传参,运行时动态分发,节省编译体积,方便持久存储,灵活易用。
13971413

1398-
而虚函数一旦用了,基本就只能动态分发了,即使能被优化掉,虚表指针也永远占据着一个 8 字节的空间,且永远只能以指针形式传来传去。
1414+
#tip[例如上面的函数,如果我们突然想要高性能了,只需把 `std::function<int(int, int)> op` 轻轻改为 `auto op` 就轻松切换到静态分发模式了。]
1415+
1416+
而虚函数一旦用了,基本就只能动态分发了,即使能被 IPO 优化掉,虚表指针也永远占据着一个 8 字节的空间,且永远只能以指针形式传来传去。
13991417

14001418
#detail[一种静态分发版的虚函数替代品是 CRTP,他基于模板元编程,但与虚函数之间切换困难,不像函数对象那么无感,之后的模板元专题章节中会专门介绍。]
14011419

14021420
=== 函数对象的动态分发用于多线程任务队列
14031421

14041422
=== 函数对象的重要机制:闭包
14051423

1424+
=== 函数指针是 C 语言陋习,改掉
1425+
14061426
== bind 为函数对象绑定参数
14071427

14081428
```cpp

misc/afdian.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import os
2+
import requests
3+
import time
4+
import hashlib
5+
import json
6+
from PIL import Image, ImageDraw, ImageFont
7+
from io import BytesIO
8+
9+
def afd_query(which, **params):
10+
user_id = '6256dedc1af911eebf8152540025c377'
11+
token = os.environ['AFDIAN_TOKEN']
12+
ts = int(time.time())
13+
params = json.dumps(params)
14+
sign = hashlib.md5(f'{token}params{params}ts{ts}user_id{user_id}'.encode('utf-8')).hexdigest()
15+
res = requests.get(f'https://afdian.net/api/open/{which}', params={
16+
'user_id': user_id,
17+
'params': params,
18+
'ts': ts,
19+
'sign': sign,
20+
}).json()
21+
assert res['ec'] == 200, res
22+
return res['data']
23+
24+
def afd_query_sponsors():
25+
i = 1
26+
while True:
27+
page = afd_query('query-sponsor', page=i)
28+
n = page['total_page']
29+
for user in page['list']:
30+
yield user
31+
if i >= n:
32+
break
33+
i += 1
34+
35+
def afd_gen_thank_list():
36+
sponsors = list(reversed(list(afd_query_sponsors())))
37+
max_y = 30
38+
for user in sponsors:
39+
max_y += 100
40+
max_y += 10
41+
img = Image.new('RGB', (800, max_y), color='#19242e')
42+
x = 30
43+
y = 30
44+
for user in sponsors:
45+
draw = ImageDraw.Draw(img)
46+
font = ImageFont.truetype('/usr/share/fonts/noto-cjk/NotoSansCJK-Medium.ttc', size=20)
47+
avatar = Image.open(BytesIO(requests.get(user['user']['avatar']).content))
48+
avatar = avatar.resize((80, 80))
49+
img.paste(avatar, (x, y))
50+
draw.text((x + 100, y), f'{user['user']['name']}', fill='white', font=font)
51+
draw.text((x + 100, y + 30), f'¥{user['all_sum_amount']}', fill='#aaaaaa', font=font)
52+
print(f'{user['user']['name']}{user['all_sum_amount']}')
53+
y += 100
54+
return img
55+
56+
img = afd_gen_thank_list()
57+
file = 'pic/thanks.png'
58+
img.save(file)
59+
os.system(f'curl -L -X PUT https://142857.red/files/afdian-thanks.png -F file=@{file} -F token={os.environ['SEVEN_TOKEN']}')

pic/thanks.png

48 KB
Loading

0 commit comments

Comments
 (0)