Created
November 1, 2013 19:32
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment