我简单阐述下背景: 我不是专业 C 开发人员, 我是 python 开发。 因为 python 部分功能实现慢,故使用 C 来重写然后进行封装动态库进行调用。 所有项目用的是 C 不是 C++ 。 目前是已经完成了 速度也有很大的提升。 但是我发现应该还能提升 。 下面代码就是一个例子。。
我要循环一个很大的值 百万级别甚至上亿。 然后动态数组, 但是这个创建动态数组非常慢,各位 C 大佬有什么方法可以解决吗? 还是说我的操作有问题??? 非专 C 人员,勿喷, 如果可以的话,救救孩纸吧.
下面迭代了 132963138 次数的耗时情况
for (int ii = 0; ii < arr_cnt_copy; ii++) {
count += 1;
int min_score = 7462; // 200 ms
int* res_card_lst = (int*)malloc(c_ * sizeof(int)); // 25s
}
1
mepwang 2022-07-05 16:11:24 +08:00
不要用循环,一次性分一大块内存,然后用指针运算来寻址
|
2
hhhhhh123 OP 上面一亿+次 迭代 还是算中等 次数, 呜呜呜 python 计算的话 要个把小时 还是 C 牛逼
|
4
ysc3839 2022-07-05 16:12:54 +08:00 3
怀疑是 X-Y Problem https://coolshell.cn/articles/10804.html
建议直接说原始需求 |
5
hsfzxjy 2022-07-05 16:13:39 +08:00 via Android
不清楚你要的业务逻辑,但如果有可能的话,把内存申请拿到循环外来做。
|
7
westoy 2022-07-05 16:14:08 +08:00
malloc 怎么可能耗时 25s , 应该是其他地方有问题
|
8
hhhhhh123 OP @hsfzxjy 我是不是可以理解为, 在循环外 创建数组 然后循环内使用, 使用完后在删除数组里面的元素? 这样就省了创建过程?
|
10
3dwelcome 2022-07-05 16:20:36 +08:00
我以前也觉得 malloc 不慢,后来查 BUG ,才发现把内存分配放在循环里,确实很慢。
预分配吧,没其他太好的办法。 |
11
SmallZheng 2022-07-05 16:22:56 +08:00
直接一次性申请 c_ * sizeof(int) * arr_cnt_copy 这么多,再自己分配
|
12
Hallelu 2022-07-05 16:25:31 +08:00
是的,将 malloc 拿出来,在循环外进行分配内存,空间换时间,大概算了下,一千万次概 38MB 左右,表示也还好
|
13
hhhhhh123 OP 兄弟们, 报喜了。。。。是要拿出来快很多了。 感谢各位。。 我也蠢了 唉 ,, 在外面定义数组 , 然后里面会赋值,下一次循环又重新赋值 这个操作 比在里面重新创建要快很多 。。。
|
14
hhhhhh123 OP 谢谢各位 i 。。解决了一个 速度问题, 我去找另外的速度问题去了 。。 么么哒
|
15
BrettD 2022-07-05 17:04:42 +08:00 via iPhone
你为什么要在循环里面申请内存呢
|
16
yolee599 2022-07-05 17:05:19 +08:00
一般这种情形都是自己撸一个内存池( doge )。我个人是不喜欢频繁使用 malloc ,free 的,最好就是一开始就预计好要使用的空间,一次性分配好,使用到程序结束
|
17
qunqun 2022-07-05 17:07:47 +08:00 via Android
纯好奇,即使 Python 也要预分配吧
|
18
villivateur 2022-07-05 17:09:59 +08:00
因为 malloc 是个比较耗时的过程
|
19
ty359 2022-07-05 17:38:31 +08:00
你这是完全没有 free 这块内存吧,C/C++初学者不要用 malloc 或者 new 这类动态内存使用方式,直接上 STL 容器对你来说容易一些。
|
21
e9pWeUbh9PGCnp95 2022-07-05 17:55:46 +08:00
由于操作系统的惰性分配有关, 请提前申请内存,并提前触发缺页中断, 这样能够确保内存立即能够使用.
|
22
ty359 2022-07-05 18:02:39 +08:00
@hhhhhh123 那你要么转用 C++,不然就多注意一点,C 不像 Python ,是没有自动内存回收的,而且例如文件描述符也是需要手动管理的,在这个角度 C 比 C++要麻烦不少;
另外你不能因为好像 C/C++比 Python 快就去改用 C/C++,你最好得明白 C/C++该怎么用;一个 C/C++新手写出来的科学计算程序可能还不如 numpy 的性能。 |
23
documentzhangx66 2022-07-05 18:19:37 +08:00
1.malloc 以及类似的内存分配、重分配、销毁等 API ,其本质是一个规划管理问题,运算量非常耗时。很多朋友只调用它一次,当然感受不到它的慢。
因此,很多大佬,会根据需求,自己实现 xxMaloc ,来根据需求定制化地管理内存,不用原生的 malloc ,来进行加速。 2.我还是建议楼主,重开一贴,专门讲讲你的需求,可能会有更好的方案。 3.楼主觉得,这个问题上 C 比 Python 强,但楼主需要思考一下,为什么 Python 还那么流行。 |
24
mxT52CRuqR6o5 2022-07-05 18:27:38 +08:00 via Android
我觉得你可以试试 c#,前几天站里有个人发语言性能排名,c#是有 gc 带 runtime 里面最快的
|
25
BrettD 2022-07-05 18:29:42 +08:00 via iPhone
@mxT52CRuqR6o5 但是 C#和 Python 互操作目前有简单的解决方案吗?
|
26
stephenyin 2022-07-05 19:11:42 +08:00
|
27
tairan2006 2022-07-05 21:22:54 +08:00
我还以为 c 里面直接声明一个超大数组是常识,当然你可以试试内存池之内的玩意儿
|
28
chenxytw 2022-07-05 22:13:28 +08:00
我的建议是,用 Cython.
|
29
ToBeHacker 2022-07-05 22:31:53 +08:00
malloc 是系统调用,频次太高也会有性能问题的
|
30
MeePawn666 2022-07-06 06:47:38 +08:00 via Android
@ToBeHacker 小杠一下,malloc 不是系统调用,底层的 brk 和 mmap 才是
|
31
LANB0 2022-07-06 10:11:31 +08:00
@tairan2006 栈区超大数组是很可能造成栈溢出的,怎么会有常识一说?楼主只是没有认识到动态内存申请是需要耗时的,把动态内存申请放在循环外即可解决,对于循环外函数频繁调用的,使用全局或者静态指针申请一次即可,内存池对非 C 开发人员来说,要求高了点。
|
32
ToBeHacker 2022-07-06 12:33:56 +08:00
@MeePawn666 是的,malloc 是 C 标准库的实现
|
33
hhhhhh123 OP 这是要我重新开个帖子, 把代码贴上 然后找优化点吗?
|
34
hhhhhh123 OP 现在优化到 200ms -> 58ms 平均,但是还是太慢了
|
35
echoechoin 2022-07-06 17:52:22 +08:00
在 github 找一个内存池用用呗, 想更快还可以使用 linux 的 hugetables 但是感觉用内存池就够了吧
|