V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
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 · 2015-11-30 19:23:46 +08:00 · 6099 次点击
    这是一个创建于 3282 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下

    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 条回复    2015-12-01 14:54:58 +08:00
    kikyous
        1
    kikyous  
       2015-11-30 19:52:43 +08:00 via Android
    你空循环试试
    kikyous
        2
    kikyous  
       2015-11-30 19:54:13 +08:00 via Android
    字符串相加代价很高,忘了是哪个语言了😁
    wy315700
        3
    wy315700  
       2015-11-30 19:56:01 +08:00
    hiredis 装了吗
    JamesRuan
        4
    JamesRuan  
       2015-11-30 20:04:45 +08:00
    @kikyous python 的 str 是 immutable 的,相连是需要复制整个数据结构的。
    wenbinwu
        5
    wenbinwu  
       2015-11-30 20:06:54 +08:00
    用 pipeline
    lichun
        6
    lichun  
       2015-11-30 20:20:12 +08:00
    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  
       2015-11-30 20:25:52 +08:00
    range 改 xrange 试试。
    lichun
        8
    lichun  
       2015-11-30 20:34:09 +08:00
    @est
    @kikyous

    并不是字符串相加和 range 的原因,估计是 redis 驱动的锅
    larkifly
        9
    larkifly  
    OP
       2015-11-30 20:51:43 +08:00
    @kikyous
    @wy315700
    @JamesRuan
    @wenbinwu
    @lichun
    @est

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