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

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

  •  
  •   hhhhhh123 · 42 天前 · 1944 次点击
    这是一个创建于 42 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    预分配吧,没其他太好的办法。
    SmallZheng
        11
    SmallZheng  
       42 天前
    直接一次性申请 c_ * sizeof(int) * arr_cnt_copy 这么多,再自己分配
    Hallelu
        12
    Hallelu  
       42 天前
    是的,将 malloc 拿出来,在循环外进行分配内存,空间换时间,大概算了下,一千万次概 38MB 左右,表示也还好
    hhhhhh123
        13
    hhhhhh123  
    OP
       42 天前
    兄弟们, 报喜了。。。。是要拿出来快很多了。 感谢各位。。 我也蠢了 唉 ,, 在外面定义数组 , 然后里面会赋值,下一次循环又重新赋值 这个操作 比在里面重新创建要快很多 。。。
    hhhhhh123
        14
    hhhhhh123  
    OP
       42 天前
    谢谢各位 i 。。解决了一个 速度问题, 我去找另外的速度问题去了 。。 么么哒
    BrettD
        15
    BrettD  
       42 天前 via iPhone
    你为什么要在循环里面申请内存呢
    yolee599
        16
    yolee599  
       42 天前
    一般这种情形都是自己撸一个内存池( doge )。我个人是不喜欢频繁使用 malloc ,free 的,最好就是一开始就预计好要使用的空间,一次性分配好,使用到程序结束
    qunqun
        17
    qunqun  
       42 天前 via Android
    纯好奇,即使 Python 也要预分配吧
    villivateur
        18
    villivateur  
       42 天前
    因为 malloc 是个比较耗时的过程
    ty359
        19
    ty359  
       42 天前
    你这是完全没有 free 这块内存吧,C/C++初学者不要用 malloc 或者 new 这类动态内存使用方式,直接上 STL 容器对你来说容易一些。
    hhhhhh123
        20
    hhhhhh123  
    OP
       42 天前
    @ty359 C 也有 vector 这种吗? 不是 C++才有吗?
    unintialized
        21
    unintialized  
       42 天前
    由于操作系统的惰性分配有关, 请提前申请内存,并提前触发缺页中断, 这样能够确保内存立即能够使用.
    ty359
        22
    ty359  
       42 天前
    @hhhhhh123 那你要么转用 C++,不然就多注意一点,C 不像 Python ,是没有自动内存回收的,而且例如文件描述符也是需要手动管理的,在这个角度 C 比 C++要麻烦不少;
    另外你不能因为好像 C/C++比 Python 快就去改用 C/C++,你最好得明白 C/C++该怎么用;一个 C/C++新手写出来的科学计算程序可能还不如 numpy 的性能。
    documentzhangx66
        23
    documentzhangx66  
       42 天前
    1.malloc 以及类似的内存分配、重分配、销毁等 API ,其本质是一个规划管理问题,运算量非常耗时。很多朋友只调用它一次,当然感受不到它的慢。

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


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


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

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