V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
wyc9296
V2EX  ›  Python

Python for 循环的效率是这么差么?还是别的什么原因?

  •  1
     
  •   wyc9296 · Aug 1, 2022 · 6200 views
    This topic created in 1365 days ago, the information mentioned may be changed or developed.

    三种写法,耗时从高到低,如下面代码所示,输出结果一样。各位大佬帮忙看下原因?

    • 第一种,耗时 7.688s
    a = ''
    for i in range(100000):
        a = a+str(i)+'->'
    
    • 第二种,耗时 0.025s
    b = ''.join([str(i)+'->' for i in range(100000)])
    
    • 第三种,耗时 0.017s
    c = '->'.join(map(str, range(100000)))+'->'
    

    输出结果:0->1->2->3->4->5->6->7->8->9...->99998->99999->

    39 replies    2022-08-02 10:01:55 +08:00
    mxT52CRuqR6o5
        1
    mxT52CRuqR6o5  
       Aug 1, 2022
    for 相比 join 会生成大量的 string 中间状态影响性能吧
    sujin190
        2
    sujin190  
       Aug 1, 2022   ❤️ 1
    你这分明是内存复制的问题,和 Python 毛关系没有吧,第一个慢的循环内存申请和复制量随着循环次数增加会指数增长,啥语言都会慢很多
    Mohanson
        3
    Mohanson  
       Aug 1, 2022
    思考下字符串加法.
    metaquant
        4
    metaquant  
       Aug 1, 2022
    这个和 python 循环的效率无关,而是因为 python 中字符串是 immutable 的,每次拼接字符串都会产生复制一个新的字符串变量,开销较大,所以涉及大量字符串拼接时,正确的做法是使用第二和第三种方法中的 join , 所以你可以发现第二和第三种方法的差距很小。
    sujin190
        5
    sujin190  
       Aug 1, 2022
    如果你在 c 或者 java 直接仅仅写这么一段也很快,那大概率是被编译器展开优化掉了,关掉编译优化再看看
    wxf666
        6
    wxf666  
       Aug 1, 2022   ❤️ 1
    你换成 a += str(i)+'->' 就差不多一样了
    LaFayette
        7
    LaFayette  
       Aug 1, 2022
    第一个时间主要花在每次循环的字符串拼接上了
    churchill
        8
    churchill  
       Aug 1, 2022
    😄
    ```
    function test() {
    a = ''
    for (let i=0; i<100000; i++) a = a+i+'->'
    return a
    }
    test()
    console.time("python sucks")
    test()
    console.timeEnd("python sucks")
    VM809:9 python sucks: 19.73193359375 ms
    ```
    lingly02
        9
    lingly02  
       Aug 1, 2022
    function test2() {[...Array(10000).keys()].map((i)=>i+'->').join('')}
    console.time("python sucks")
    test2()
    console.timeEnd("python sucks")
    VM1332:3 python sucks: 1.7998046875 ms
    nekochyan
        10
    nekochyan  
       Aug 1, 2022
    第一个你是不是看错时间了,不是 7.8s 而是 0.78s ,我实测耗时 0.8s 左右
    js 测试我跟楼上一样只需要 13ms 左右就完成循环了
    wxf666
        11
    wxf666  
       Aug 1, 2022
    这个例子中,Google 花这么多钱搞的 V8 ,也没甩开 Python 多少啊?

    这 8 楼 9 楼( 9 楼还少了个数量级)和楼主的没 JIT 的 Python 一比(第一个例子改成 += 就好),也没快多少啊
    ipwx
        12
    ipwx  
       Aug 1, 2022
    无论什么语言,大量小字符串直接拼接都会有严重的性能问题。
    aloxaf
        13
    aloxaf  
       Aug 1, 2022
    见 wtrfpython: https://github.com/satwikkansal/wtfpython#section-miscellaneous

    顺便本机测了一下,方法一 700 ms ,换 bytearray 只要 20ms

    a = bytearray()
    for i in range(100000):
    a.extend((str(i) + '->').encode())
    a = a.decode()
    wyc9296
        14
    wyc9296  
    OP
       Aug 1, 2022
    @nekochyan 没错,是因为你的电脑 CPU 比较给力。我的电脑在跑的时候 4 个核中的一个已经用了 100%了...你可以把循环次数*10 ,应该就能看出来明显的差别了。
    应该就是和 @metaquant 大佬所说的和 python 的不可变对象有关系。用 @wxf666 兄弟的办法`a += str(i)+'->' `可以看到耗时虽然比不上 join ,但也明显降低了。
    wxf666
        15
    wxf666  
       Aug 1, 2022
    @wyc9296 你把 str(i)+'->' 改成 f'{i}->' 应该还能再快些
    xgdgsc
        16
    xgdgsc  
       Aug 1, 2022 via Android
    就是很差的,julia 用 PythonCall.jl 用 julia 的 for 循环调用 python 函数随便比 python 快几个数量级
    houzhiqiang
        17
    houzhiqiang  
       Aug 1, 2022
    ```python
    import time


    def test(n: int = 100000):
    # return '->'.join([f'{x}' for x in range(n)]) + '->'
    return '->'.join(map(str, range(n))) + '->'


    start = time.time()
    test()
    print(f"used: {(time.time() - start) * 1000}ms")
    ```

    cpython3.10.3
    time python test.py
    used: 19.52505111694336ms
    python test.py 0.05s user 0.03s system 87% cpu 0.096 total

    pypy3.9-7.3.9
    time pypy test.py
    used: 7.740020751953125ms
    pypy test.py 0.06s user 0.04s system 89% cpu 0.118 total

    #9 @lingly02 的代码
    node v16.14.2
    time node test.js
    python sucks: 3.757ms
    node test.js 0.05s user 0.02s system 95% cpu 0.069 total
    wxf666
        18
    wxf666  
       Aug 1, 2022
    @xgdgsc 不会吧,就算那个测评榜,C/C++ 之类也就比 Python 快两个数量级,你这啥能 3+ 个?
    wxf666
        19
    wxf666  
       Aug 1, 2022
    @houzhiqiang 看起来日用差距不大,真要求性能,还是上 C/C++ 之类的吧,wasm 都没用(比如 squoosh 转码 avif ,比本地 avifenc 慢太多)
    HankLu
        20
    HankLu  
       Aug 1, 2022
    判断一个字符串是否在一个巨大的文本里面怎么样最快?
    houzhiqiang
        21
    houzhiqiang  
       Aug 1, 2022
    #8 @churchill 的代码
    node v16.14.2
    time node test.js
    python sucks: 26.584ms
    node test.js 0.10s user 0.02s system 98% cpu 0.124 total

    #9 @lingly02 的代码 把他的 Array(10000)换成 Array(100000)
    node v16.14.2
    time node test.js
    python sucks: 24.985ms
    node test.js 0.06s user 0.02s system 97% cpu 0.084 total

    @houzhiqiang
    houzhiqiang
        22
    houzhiqiang  
       Aug 1, 2022
    @wxf666 cpython3.10 比 #8 @churchill 稍快一点
    wxf666
        23
    wxf666  
       Aug 1, 2022
    @houzhiqiang 嗯?我第一眼看你 17 楼,以为 v8 比 pypy 快一倍,比 cpython 快五倍呢,

    原来你是用了 少一个数量级 那个代码啊。。
    wxf666
        24
    wxf666  
       Aug 1, 2022
    @HankLu 其他帖子有大佬说过,Python 的 in 用了介于 Boyer-Moore 和 Horspool 之间的算法,比 KMP 快

    还不满足的话,你可以问问 @xgdgsc #16 ,

    按他说法,那个啥语言随便起来比 Python 快几个数量级(假设 3 个),那严肃起来还要再快 1~2 个

    有个排行榜说,C/C++ 比 Python 快 2 个数量级,

    综合算下来,那个啥语言严肃地写,可以比 C/C++ 快 1~3 个数量级
    churchill
        25
    churchill  
       Aug 1, 2022
    这。。。我就是打个趣,代码是按楼主的第一种写法原封不动搬来的
    性能这个事情 python 也还是要挣扎一下吗,大可不必
    黑魔法的话 js 也有呀
    warm 一下立杆见影
    test()
    setTimeout(() => {
    console.time("python sucks")
    test()
    console.timeEnd("python sucks")
    })
    lingly02
        26
    lingly02  
       Aug 1, 2022 via iPhone
    @houzhiqiang 上班摸鱼,看错数量了,😅
    wxf666
        27
    wxf666  
       Aug 1, 2022   ❤️ 2
    @churchill 感觉就像娱乐圈明星某些粉丝的行为,别人讨论点不相干的啥都来踩一脚。。

    “我家 xxx 最棒!”

    我不是哪个语言的粉,有更合适的就学着用
    Elaina
        28
    Elaina  
       Aug 1, 2022
    是字符串拼接影响效率,你把字符串拼接改成空操作,就没这么夸张了
    churchill
        29
    churchill  
       Aug 1, 2022
    @wxf666 伤害到你的感情了,我很抱歉,对不起,python 好棒棒 😄
    zhuweiyou
        30
    zhuweiyou  
       Aug 1, 2022
    字符串拼接的问题
    xgdgsc
        31
    xgdgsc  
       Aug 1, 2022
    @wxf666 for 循环里先读取 memmap 的 array 里一个数,然后调用函数,这种情况反正用 julia 比 python 至少快一个数量级,我用几只不过想不起来具体快多少了,并不是说一定大于等于 3 才用几.
    HankLu
        32
    HankLu  
       Aug 1, 2022
    @wxf666 其实很满意 Python 的 in 操作,就是想找更快的
    w3cll
        33
    w3cll  
       Aug 1, 2022
    蹲一个 PHP 的
    liKeYunKeji
        34
    liKeYunKeji  
       Aug 1, 2022
    ```
    <?php

    $starttime = explode(' ',microtime());
    for($i=0; $i<100000; $i++){
    echo $i.'<br/>';
    }
    $endtime = explode(' ',microtime());
    $thistime = $endtime[0]+$endtime[1]-($starttime[0]+$starttime[1]);
    $thistime = round($thistime,3);
    echo '用时'.$thistime;

    ?>
    ```

    <img src="https://sc01.alicdn.com/kf/Ha0b06a519774459597cb42b339bd7ecbx.png" />


    @w3cll
    wxf666
        35
    wxf666  
       Aug 2, 2022
    @churchill 嗯,我痛心疾首

    那 21 楼会让你如丧考妣
    wxf666
        36
    wxf666  
       Aug 2, 2022
    @HankLu 你可以去问问 @churchill ,毕竟 js 是世界上最好的语言,写出来的代码有着 O(1/N) 复杂度,区区一个大文件算得了什么,某些机构对世界的监控就是用 js 做搜索的
    Aloento
        37
    Aloento  
       Aug 2, 2022
    @wxf666 你在说什么(((
    jinliming2
        38
    jinliming2  
       Aug 2, 2022 via iPhone
    @pytth #34 你这个 echo 是流输出啊,不是字符串拼接,有点作弊了哦……
    Anivial
        39
    Anivial  
       Aug 2, 2022
    一个提问贴能多这么多阴阳怪气的人也是没谁了,以后看见歪楼的就走,无语死
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3200 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 71ms · UTC 13:41 · PVG 21:41 · LAX 06:41 · JFK 09:41
    ♥ Do have faith in what you're doing.