- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一组 python 代码,比方说 item_ids
item_ids = {1, 2, 3, 4, 5}
而且我还有一个预先计算好的 redis 集,items_with_property
127.0.0.1:6379> SADD items_with_property 3 4 5 6
(integer) 5
127.0.0.1:6379> SMEMBERS items_with_property
1) "3"
2) "4"
3) "5"
4) "6"
是否有可能在不将 items_with_property 提取到 python 内存的情况下将 item_ids 与 items_with_property 相交?
我想要类似的东西
>>> print(redis_client.magic_sinter(item_ids, 'items_with_property'))
{3, 4, 5}
这样做的原因是 items_with_property 和 item_ids 可以非常大,我不想在服务器之间传输大量数据(redis 是在单独的机器上,并且有很多客户)
更新 2019-02-05
我为不同的方法准备了一个速度测试,这是我的结果:
from django.core.cache import caches
from django.utils.functional import cached_property
from django_redis import get_redis_connection
from hot_redis import Set
search_storage = caches['search.filter']
class Command(BaseCommand):
command_name = 'performance_test'
def handle(self, *args, **options):
"""
output:
1
TEST1 results time: 13.432172060012817
TEST2 results time: 4.478500127792358
TEST3 results time: 4.45565390586853
TEST4 results time: 4.674767732620239
TEST5 results time: 3.244804859161377
TEST6 results time: 4.4963860511779785
2
TEST1 results time: 13.012064695358276
TEST2 results time: 4.4086668491363525
TEST3 results time: 4.4962310791015625
TEST4 results time: 4.745664119720459
TEST5 results time: 3.3029701709747314
TEST6 results time: 4.676959991455078
3
TEST1 results time: 12.83815312385559
TEST2 results time: 4.190127849578857
TEST3 results time: 4.445873260498047
TEST4 results time: 4.724813938140869
TEST5 results time: 3.2511937618255615
TEST6 results time: 4.454891920089722
4
TEST1 results time: 13.131163358688354
TEST2 results time: 4.265545129776001
TEST3 results time: 4.440964221954346
TEST4 results time: 4.571079969406128
TEST5 results time: 3.279599189758301
TEST6 results time: 4.366865873336792
5
TEST1 results time: 13.424093961715698
TEST2 results time: 4.349413156509399
TEST3 results time: 4.42648720741272
TEST4 results time: 4.607520818710327
TEST5 results time: 3.415123224258423
TEST6 results time: 4.391672134399414
"""
item_ids = set(random.sample(range(10000000, 1000000000), 100000)) # 100k random ints
# TEST1 - PYTHON INTERSECTION
_started_at = time.time()
_key = f'test1'
search_storage.set(_key, item_ids) # python pickled set
for _ in range(1000):
search_ids = set(random.sample(item_ids, k=100))
redis_ids = search_storage.get(_key)
result = search_ids & redis_ids
assert len(result) == 100
search_storage.delete(_key)
print("TEST1 results time: ", time.time() - _started_at)
# TEST2 - REDIS INTERSECTION, using stored function and SISMEMBER for every search_id
_started_at = time.time()
_key = f'test2'
redis_con = get_redis_connection('search.filter') # raw connetction for redis methods.
redis_con.sadd(_key, *item_ids)
stored_func = redis_con.register_script('''
local reply = {}
while #ARGV > 0 do
local member = table.remove(ARGV)
if redis.call('SISMEMBER', KEYS[1], member) == 1 then
table.insert(reply, member)
end
end
return reply
''')
for _ in range(1000):
search_ids = random.sample(item_ids, k=100)
result = stored_func(keys=[_key], args=search_ids)
assert len(result) == 100
redis_con.delete(_key)
print("TEST2 results time: ", time.time() - _started_at)
# TEST3 - REDIS INTERSECTION, using python-made temp key
_started_at = time.time()
_key = f'test3'
redis_con = get_redis_connection('search.filter')
redis_con.sadd(_key, *item_ids)
for _ in range(1000):
search_ids = frozenset(random.sample(item_ids, k=100))
_temp_key = f'test3_temp_{hash(search_ids)}'
redis_con.sadd(_temp_key, *search_ids)
result = redis_con.sinter(keys=[_key, _temp_key])
redis_con.delete(_temp_key)
assert len(result) == 100
redis_con.delete(_key)
print("TEST3 results time: ", time.time() - _started_at)
# TEST4 - REDIS INTERSECTION, using stored function and redis-made temp key
_started_at = time.time()
_key = f'test4'
redis_con = get_redis_connection('search.filter')
redis_con.sadd(_key, *item_ids)
stored_func = redis_con.register_script('''
local reply = {}
local temp_key = KEYS[1]
redis.call('SADD', temp_key, unpack(ARGV))
reply = redis.call('SINTER', temp_key, KEYS[2])
redis.call('DEL', temp_key)
return reply
''')
for _ in range(1000):
search_ids = frozenset(random.sample(item_ids, k=100))
_temp_key = f'test4_temp_{hash(search_ids)}'
result = stored_func(keys=[_temp_key, _key], args=search_ids)
assert len(result) == 100
redis_con.delete(_key)
print("TEST4 results time: ", time.time() - _started_at)
# TEST5 - PYTHON INTERSECTION, using cached_property
_started_at = time.time()
_key = f'test5'
search_storage.set(_key, item_ids, SEARCH_FILTER_TIMEOUT)
for _ in range(1000):
search_ids = set(random.sample(item_ids, k=100))
redis_ids = self.cached_cached_item_ids
result = search_ids & redis_ids
assert len(result) == 100
search_storage.delete(_key)
print("TEST5 results time: ", time.time() - _started_at)
# TEST6 - HOT REDIS
_started_at = time.time()
_key = f'test6'
hot_items = Set(key=_key, initial=item_ids)
for _ in range(1000):
search_ids = Set(initial=random.sample(item_ids, k=100))
result = hot_items & search_ids
search_ids.clear()
assert len(result) == 100
hot_items.clear()
print("TEST6 results time: ", time.time() - _started_at)
@cached_property
def cached_cached_item_ids(self):
return search_storage.get('test5')
你可以自己试试,这是一个Django命令,但我认为重点很明确。
获胜者是 TEST5 - “本地缓存”缓存结果。我们大大减少了序列化数据的次数,但我们还有另一个头疼的问题 - 如何使第二层缓存失效。
对我来说,赢家是 hot-redis - python 库已经实现了所有合适的 lua methods ,并且有干净的界面。
最佳答案
使用 Lua(另一种语言)在任何语言中都有一种神奇的方法可以做到这一点。参见 Redis 的 EVAL
和 redis-py 的 Script
辅助类。
脚本需要 Redis 集的键名和代表客户端集的任意数量的附加参数('item_ids')。对于每个参数,它对目标集执行 SISMEMBER
操作以确定相交。
from redis import Redis
items_with_property = [3, 4, 5, 6]
item_ids = [1, 2, 3, 4, 5]
r = Redis()
r.sadd('items_with_property', *items_with_property)
s = r.register_script('''
local reply = {}
while #ARGV > 0 do
local member = table.remove(ARGV)
if redis.call('SISMEMBER', KEYS[1], member) == 1 then
table.insert(reply, member)
end
end
return reply
''')
print(s(keys=['items_with_property'], args=item_ids))
注意:另一种方法是使用临时 key 来存储用户提供的成员,然后对源集和临时集执行 SINTER
操作。对于较大的本地 Set,这应该会表现更好。
关于python - 如何将python集与redis集相交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54501235/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!