Skip to content

Instantly share code, notes, and snippets.

@josiahcarlson
Created November 1, 2013 19:32
Show Gist options
  • Save josiahcarlson/7270690 to your computer and use it in GitHub Desktop.
Save josiahcarlson/7270690 to your computer and use it in GitHub Desktop.
This tests example Redis intersection vs. a manual Lua intersection. Released into the public domain.
import time
import redis
def _script_load(script):
'''
Borrowed from my book, Redis in Action:
https://github.com/josiahcarlson/redis-in-action/blob/master/python/ch11_listing_source.py
'''
sha = [None]
def call(conn, keys=[], args=[], force_eval=False):
if not force_eval:
if not sha[0]:
sha[0] = conn.execute_command(
"SCRIPT", "LOAD", script, parse="LOAD")
try:
return conn.execute_command(
"EVALSHA", sha[0], len(keys), *(keys+args))
except redis.exceptions.ResponseError as msg:
if not msg.args[0].startswith("NOSCRIPT"):
raise
return conn.execute_command(
"EVAL", script, len(keys), *(keys+args))
return call
def setup_range(conn, key, size):
pipe = conn.pipeline(False)
pipe.delete(key, key+'+', key+'-')
for i in xrange(size):
pipe.zadd(key, i, i)
if i & 1:
pipe.zadd(key+'-', i, i)
if not i % 1000:
pipe.execute()
pipe.execute()
def test_copy(conn, key, count):
for i in xrange(count):
conn.zinterstore(key+'+', [key, key+'-'])
def test_copy_delete(conn, key, start, end, count):
pipe = conn.pipeline(True)
for i in xrange(count):
pipe.zinterstore(key+'+', [key, key+'-'])
pipe.zremrangebyscore(key+'+', '-inf', start)
pipe.zremrangebyscore(key+'+', end, 'inf')
pipe.execute()
def test_lua_copy(conn, key, start, end, count):
for i in xrange(count):
lua_copy(conn, [key, key+'+', key+'-'], [start, end])
lua_copy = _script_load('''
redis.call('del', KEYS[2])
local index = 0
local data
repeat
data = redis.call('zrangebyscore', KEYS[1], ARGV[1], ARGV[2], 'withscores', 'limit', index, 1000)
if #data > 0 then
for j = 1, #data, 2 do
if redis.call('zscore', KEYS[3], data[j]) then
redis.call('zadd', KEYS[2], data[j+1], data[j])
end
end
redis.call('zadd', KEYS[2], unpack(data))
end
index = index + 1000
until #data < 2000
return index - 1000 + #data / 2
''')
def step(now=None):
if now is None:
return time.time()
return time.time() - now
if __name__ == '__main__':
conn = redis.Redis()
for size in [1000, 2500, 5000, 10000, 25000, 50000, 100000]:
count = 1000000 / size
setup_range(conn, 'key', size)
t = step()
test_copy(conn, 'key', count)
print "tc ", size, step(t)
for ws, we in [(.45, .50), (.48, .52), (.48, .51), (.49, .51), (.49, .5)]:
start = int(ws * size)
end = int(we * size)
t = step()
test_copy_delete(conn, 'key', start, end, count)
print "tcd", size, we-ws, step(t)
# to keep it fair
conn.delete('key+')
t = step()
test_lua_copy(conn, 'key', start, end, count)
print "tlc", size, we-ws, step(t)
print
print
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment