V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hhhhhh123
V2EX  ›  C

C 语言 循环下 创建动态数组 非常慢 应该如何解决

  •  
  •   hhhhhh123 · 2022-07-05 16:07:03 +08:00 · 2872 次点击
    这是一个创建于 871 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我简单阐述下背景: 我不是专业 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
    

    }

    35 条回复    2022-07-06 17:52:22 +08:00
    mepwang
        1
    mepwang  
       2022-07-05 16:11:24 +08:00
    不要用循环,一次性分一大块内存,然后用指针运算来寻址
    hhhhhh123
        2
    hhhhhh123  
    OP
       2022-07-05 16:11:26 +08:00
    上面一亿+次 迭代 还是算中等 次数, 呜呜呜 python 计算的话 要个把小时 还是 C 牛逼
    hhhhhh123
        3
    hhhhhh123  
    OP
       2022-07-05 16:11:49 +08:00
    @mepwang 可以详细说说吗? 我不是很懂 现学现用
    ysc3839
        4
    ysc3839  
       2022-07-05 16:12:54 +08:00   ❤️ 3
    怀疑是 X-Y Problem https://coolshell.cn/articles/10804.html
    建议直接说原始需求
    hsfzxjy
        5
    hsfzxjy  
       2022-07-05 16:13:39 +08:00 via Android
    不清楚你要的业务逻辑,但如果有可能的话,把内存申请拿到循环外来做。
    hhhhhh123
        6
    hhhhhh123  
    OP
       2022-07-05 16:13:44 +08:00
    @ysc3839 需求可就太多了 一下次说不太情况
    westoy
        7
    westoy  
       2022-07-05 16:14:08 +08:00
    malloc 怎么可能耗时 25s , 应该是其他地方有问题
    hhhhhh123
        8
    hhhhhh123  
    OP
       2022-07-05 16:16:37 +08:00
    @hsfzxjy 我是不是可以理解为, 在循环外 创建数组 然后循环内使用, 使用完后在删除数组里面的元素? 这样就省了创建过程?
    hhhhhh123
        9
    hhhhhh123  
    OP
       2022-07-05 16:17:07 +08:00
    @westoy 这个是真实的 测试代码就一个循环 一个计数 一个创建动态数组 和上面一样的
    3dwelcome
        10
    3dwelcome  
       2022-07-05 16:20:36 +08:00
    我以前也觉得 malloc 不慢,后来查 BUG ,才发现把内存分配放在循环里,确实很慢。

    预分配吧,没其他太好的办法。
    SmallZheng
        11
    SmallZheng  
       2022-07-05 16:22:56 +08:00
    直接一次性申请 c_ * sizeof(int) * arr_cnt_copy 这么多,再自己分配
    Hallelu
        12
    Hallelu  
       2022-07-05 16:25:31 +08:00
    是的,将 malloc 拿出来,在循环外进行分配内存,空间换时间,大概算了下,一千万次概 38MB 左右,表示也还好
    hhhhhh123
        13
    hhhhhh123  
    OP
       2022-07-05 16:32:21 +08:00
    兄弟们, 报喜了。。。。是要拿出来快很多了。 感谢各位。。 我也蠢了 唉 ,, 在外面定义数组 , 然后里面会赋值,下一次循环又重新赋值 这个操作 比在里面重新创建要快很多 。。。
    hhhhhh123
        14
    hhhhhh123  
    OP
       2022-07-05 16:33:58 +08:00
    谢谢各位 i 。。解决了一个 速度问题, 我去找另外的速度问题去了 。。 么么哒
    BrettD
        15
    BrettD  
       2022-07-05 17:04:42 +08:00 via iPhone
    你为什么要在循环里面申请内存呢
    yolee599
        16
    yolee599  
       2022-07-05 17:05:19 +08:00
    一般这种情形都是自己撸一个内存池( doge )。我个人是不喜欢频繁使用 malloc ,free 的,最好就是一开始就预计好要使用的空间,一次性分配好,使用到程序结束
    qunqun
        17
    qunqun  
       2022-07-05 17:07:47 +08:00 via Android
    纯好奇,即使 Python 也要预分配吧
    villivateur
        18
    villivateur  
       2022-07-05 17:09:59 +08:00
    因为 malloc 是个比较耗时的过程
    ty359
        19
    ty359  
       2022-07-05 17:38:31 +08:00
    你这是完全没有 free 这块内存吧,C/C++初学者不要用 malloc 或者 new 这类动态内存使用方式,直接上 STL 容器对你来说容易一些。
    hhhhhh123
        20
    hhhhhh123  
    OP
       2022-07-05 17:49:20 +08:00
    @ty359 C 也有 vector 这种吗? 不是 C++才有吗?
    e9pWeUbh9PGCnp95
        21
    e9pWeUbh9PGCnp95  
       2022-07-05 17:55:46 +08:00
    由于操作系统的惰性分配有关, 请提前申请内存,并提前触发缺页中断, 这样能够确保内存立即能够使用.
    ty359
        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 的性能。
    documentzhangx66
        23
    documentzhangx66  
       2022-07-05 18:19:37 +08:00
    1.malloc 以及类似的内存分配、重分配、销毁等 API ,其本质是一个规划管理问题,运算量非常耗时。很多朋友只调用它一次,当然感受不到它的慢。

    因此,很多大佬,会根据需求,自己实现 xxMaloc ,来根据需求定制化地管理内存,不用原生的 malloc ,来进行加速。


    2.我还是建议楼主,重开一贴,专门讲讲你的需求,可能会有更好的方案。


    3.楼主觉得,这个问题上 C 比 Python 强,但楼主需要思考一下,为什么 Python 还那么流行。
    mxT52CRuqR6o5
        24
    mxT52CRuqR6o5  
       2022-07-05 18:27:38 +08:00 via Android
    我觉得你可以试试 c#,前几天站里有个人发语言性能排名,c#是有 gc 带 runtime 里面最快的
    BrettD
        25
    BrettD  
       2022-07-05 18:29:42 +08:00 via iPhone
    @mxT52CRuqR6o5 但是 C#和 Python 互操作目前有简单的解决方案吗?
    stephenyin
        26
    stephenyin  
       2022-07-05 19:11:42 +08:00
    @mxT52CRuqR6o5 #24 OP 的环境 c++ 都跑不起来,C# 更没可能咯。

    话说 OP 应该给项目提议招个 C/C++ 程序员。
    tairan2006
        27
    tairan2006  
       2022-07-05 21:22:54 +08:00
    我还以为 c 里面直接声明一个超大数组是常识,当然你可以试试内存池之内的玩意儿
    chenxytw
        28
    chenxytw  
       2022-07-05 22:13:28 +08:00
    我的建议是,用 Cython.
    ToBeHacker
        29
    ToBeHacker  
       2022-07-05 22:31:53 +08:00
    malloc 是系统调用,频次太高也会有性能问题的
    MeePawn666
        30
    MeePawn666  
       2022-07-06 06:47:38 +08:00 via Android
    @ToBeHacker 小杠一下,malloc 不是系统调用,底层的 brk 和 mmap 才是
    LANB0
        31
    LANB0  
       2022-07-06 10:11:31 +08:00
    @tairan2006 栈区超大数组是很可能造成栈溢出的,怎么会有常识一说?楼主只是没有认识到动态内存申请是需要耗时的,把动态内存申请放在循环外即可解决,对于循环外函数频繁调用的,使用全局或者静态指针申请一次即可,内存池对非 C 开发人员来说,要求高了点。
    ToBeHacker
        32
    ToBeHacker  
       2022-07-06 12:33:56 +08:00
    @MeePawn666 是的,malloc 是 C 标准库的实现
    hhhhhh123
        33
    hhhhhh123  
    OP
       2022-07-06 14:00:46 +08:00
    这是要我重新开个帖子, 把代码贴上 然后找优化点吗?
    hhhhhh123
        34
    hhhhhh123  
    OP
       2022-07-06 14:08:52 +08:00
    现在优化到 200ms -> 58ms 平均,但是还是太慢了
    echoechoin
        35
    echoechoin  
       2022-07-06 17:52:22 +08:00
    在 github 找一个内存池用用呗, 想更快还可以使用 linux 的 hugetables 但是感觉用内存池就够了吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1018 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:50 · PVG 06:50 · LAX 14:50 · JFK 17:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.