推荐学习书目
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 · 6677 views
    This topic created in 3836 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
        1
    kikyous  
       Nov 30, 2015 via Android
    你空循环试试
    kikyous
        2
    kikyous  
       Nov 30, 2015 via Android
    字符串相加代价很高,忘了是哪个语言了😁
    wy315700
        3
    wy315700  
       Nov 30, 2015
    hiredis 装了吗
    JamesRuan
        4
    JamesRuan  
       Nov 30, 2015
    @kikyous python 的 str 是 immutable 的,相连是需要复制整个数据结构的。
    wenbinwu
        5
    wenbinwu  
       Nov 30, 2015
    用 pipeline
    lichun
        6
    lichun  
       Nov 30, 2015
    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
        7
    est  
       Nov 30, 2015
    range 改 xrange 试试。
    lichun
        8
    lichun  
       Nov 30, 2015
    @est
    @kikyous

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

    目前看来是 redis-py 本身的问题,用 pipeline 效率会提升很多。经过实际的测试发现, redis-py 只开启了一个连接连到 redis-server ,那么,大量写的时候,会出现锁、排队的情况。而且, redis-py 的 keepalive 并没有让我感觉到使用的 tcp 长链。如果是长链,那么效果应该和 pipeline 差不多,即使差,也不会差很多。
    sunus
        10
    sunus  
       Nov 30, 2015
    用 pipeline 应该能到 2s 以内
    odirus
        11
    odirus  
       Nov 30, 2015
    我现在已经很少直接操作 redis 了,都是配合 lua 一起使用,并发性得到大大地提升。
    cheng007
        12
    cheng007  
       Nov 30, 2015
    Macbook air 用了 11s , 1s 写 1w 次算很慢吗?
    binux
        13
    binux  
       Nov 30, 2015   ❤️ 2
    不管换什么语言, aa.set 都需要等 TCP 包一个来回, 即使 keep-alive, 即使 redis 很快, 但是这个时间放大到 100000 次. 我觉得这个速度很正常.
    tabris17
        14
    tabris17  
       Nov 30, 2015 via iPhone
    Tcp 通信的开销,很正常吧。所以才要 pipline
    zts1993
        15
    zts1993  
       Nov 30, 2015
    我会说 Jedis 局域网内只有 7k ops 么。。你这个已经算快的了,,要想快 pipeline 和多线程。。。
    lenran
        16
    lenran  
       Nov 30, 2015
    @binux 13 楼正解
    sujin190
        17
    sujin190  
       Nov 30, 2015
    1 万多每秒,单线程,可以了吧,又不是内存写
    sometimesna1ve
        18
    sometimesna1ve  
       Dec 1, 2015
    批量操作一定要使用 pipeline.
    不久前刚做过一个小测试, 下面的 blog 是我的测试记录
    http://www.rockyqi.net/redis-intro-and-a-simple-performance-test-for-batch-operations.html
    fordoo
        19
    fordoo  
       Dec 1, 2015
    试试 low level 的 credis 速度直逼 pylibmc
    latyas
        20
    latyas  
       Dec 1, 2015
    问题略有问题,要想知道是不是 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
        21
    larkifly  
    OP
       Dec 1, 2015
    @latyas 你这个没有处理返回的情况啊
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   6009 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 88ms · UTC 02:08 · PVG 10:08 · LAX 19:08 · JFK 22:08
    ♥ Do have faith in what you're doing.