推荐学习书目
› 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
larkifly
V2EX  ›  Python

python 写 redis 为何如此的慢????

  •  
  •   larkifly · Nov 30, 2015 · 7119 views
    This topic created in 3995 days ago, the information mentioned may be changed or developed.

    代码如下

    import redis
    dd = redis.ConnectionPool(max_connections=100, socket_keepalive=True)
    aa = redis.Redis(connection_pool=dd)
    import time
    temps = 'ksljdfldksjfklsldkfjkdsjflkdsjflkdsklskdjfljewl'
    for i in range(1, 100000):
        aa.set(temps+str(i), temps)
    

    这段代码运行完,花了七秒多?一定是我姿势不对,不应该这么慢啊

    21 replies  •  2015-12-01 14:54:58 +08:00
    kikyous
    kikyous
    Nov 30, 2015 via Android
    1
    你空循环试试
    kikyous
    kikyous
    Nov 30, 2015 via Android
    2
    字符串相加代价很高,忘了是哪个语言了😁
    wy315700
    wy315700
    Nov 30, 2015
    3
    hiredis 装了吗
    JamesRuan
    JamesRuan
    Nov 30, 2015
    4
    @kikyous python 的 str 是 immutable 的,相连是需要复制整个数据结构的。
    wenbinwu
    wenbinwu
    Nov 30, 2015
    5
    用 pipeline
    lichun
    lichun
    Nov 30, 2015
    6
    In [15]: pool = redis.ConnectionPool(host='localhost', port=6379, db=0)

    In [16]: r = redis.Redis(connection_pool=pool)

    In [17]: def test_redis():
    ....: for i in range(100000):
    ....: r.set(str(i), 'test')
    ....:

    In [18]: %time test_redis()
    CPU times: user 5.9 s, sys: 1.53 s, total: 7.42 s
    Wall time: 10.9 s
    est
    est
    Nov 30, 2015
    7
    range 改 xrange 试试。
    lichun
    lichun
    Nov 30, 2015
    8
    @est
    @kikyous

    并不是字符串相加和 range 的原因,估计是 redis 驱动的锅
    larkifly
    larkifly
    OP
    Nov 30, 2015
    9
    @kikyous
    @wy315700
    @JamesRuan
    @wenbinwu
    @lichun
    @est

    目前看来是 redis-py 本身的问题,用 pipeline 效率会提升很多。经过实际的测试发现, redis-py 只开启了一个连接连到 redis-server ,那么,大量写的时候,会出现锁、排队的情况。而且, redis-py 的 keepalive 并没有让我感觉到使用的 tcp 长链。如果是长链,那么效果应该和 pipeline 差不多,即使差,也不会差很多。
    sunus
    sunus
    Nov 30, 2015
    10
    用 pipeline 应该能到 2s 以内
    odirus
    odirus
    Nov 30, 2015
    11
    我现在已经很少直接操作 redis 了,都是配合 lua 一起使用,并发性得到大大地提升。
    cheng007
    cheng007
    Nov 30, 2015
    12
    Macbook air 用了 11s , 1s 写 1w 次算很慢吗?
    binux
    binux
    Nov 30, 2015❤️2
    13
    不管换什么语言, aa.set 都需要等 TCP 包一个来回, 即使 keep-alive, 即使 redis 很快, 但是这个时间放大到 100000 次. 我觉得这个速度很正常.
    tabris17
    tabris17
    Nov 30, 2015 via iPhone
    14
    Tcp 通信的开销,很正常吧。所以才要 pipline
    zts1993
    zts1993
    Nov 30, 2015
    15
    我会说 Jedis 局域网内只有 7k ops 么。。你这个已经算快的了,,要想快 pipeline 和多线程。。。
    lenran
    lenran
    Nov 30, 2015
    16
    @binux 13 楼正解
    sujin190
    sujin190
    Nov 30, 2015
    17
    1 万多每秒,单线程,可以了吧,又不是内存写
    sometimesna1ve
    sometimesna1ve
    Dec 1, 2015
    18
    批量操作一定要使用 pipeline.
    不久前刚做过一个小测试, 下面的 blog 是我的测试记录
    http://www.rockyqi.net/redis-intro-and-a-simple-performance-test-for-batch-operations.html
    fordoo
    fordoo
    Dec 1, 2015
    19
    试试 low level 的 credis 速度直逼 pylibmc
    latyas
    latyas
    Dec 1, 2015
    20
    问题略有问题,要想知道是不是 python 的坑,参考如下代码
    单连接单线程的情况

    ```python
    import socket
    import time


    conn = socket.socket()
    conn.connect(('127.0.0.1', 6379))

    _ = time.time()
    for i in range(100000):
    #print(i)
    foo = 'ksljdfldksjfklsldkfjkdsjflkdsjflkdsklskdjfljewl' + str(i)
    bar = 'ksljdfldksjfklsldkfjkdsjflkdsjflkdsklskdjfljewl'
    command = 'SET %s %s\r\n' % (foo, bar)
    conn.send(command.encode('utf-8'))
    print('total', time.time() - _)
    ```


    ```shell
    total 0.10007500648498535
    ```

    开 10 个 worker 的进程池, 10 个 tcp 链接

    ```python
    import socket
    import time
    import multiprocessing

    def process(n):
    conn = socket.socket()
    conn.connect(('127.0.0.1', 6379))
    for i in range(10000):
    #print(i)
    foo = 'ksljdfldksjfklsldkfjkdsjflkdsjflkdsklskdjfljewl' + str(i)
    bar = 'ksljdfldksjfklsldkfjkdsjflkdsjflkdsklskdjfljewl'
    command = 'SET %s %s\r\n' % (foo, bar)
    conn.send(command.encode('utf-8'))

    pool = multiprocessing.Pool(10)
    _ = time.time()
    pool.map(process, range(10))
    print('total', time.time() - _)
    ```

    ```shell
    total 0.029608488082885742
    ```


    如果这么慢,是不是驱动上有坑?
    larkifly
    larkifly
    OP
    Dec 1, 2015
    21
    @latyas 你这个没有处理返回的情况啊
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   659 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 65ms · UTC 21:34 · PVG 05:34 · LAX 13:34 · JFK 16:34
    ♥ Do have faith in what you're doing.