簡體   English   中英

將數據保存在 memory 和 Redis 中的最快方法 Python

[英]Fastest way to keep data in memory with Redis in Python

我需要在帶有 Python 的 flask 應用程序中保存一次並加載一些大的 arrays 的倍數 3. 我最初將這些 arrays 與 json 庫一起存儲在磁盤上。 為了加快速度,我在同一台機器上使用 Redis 通過將數組序列化為 JSON 字符串來存儲數組。 我想知道為什么我沒有任何改進(實際上它在我使用的服務器上花費了更多時間)而 Redis 將數據保存在 RAM 中。 我猜 JSON 序列化沒有優化,但我不知道如何加快它:

import json
import redis
import os 
import time

current_folder = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_folder, "my_file")

my_array = [1]*10000000

with open(file_path, 'w') as outfile:
    json.dump(my_array, outfile)

start_time = time.time()
with open(file_path, 'r') as infile:
    my_array = json.load(infile)
print("JSON from disk  : ", time.time() - start_time)

r = redis.Redis()
my_array_as_string = json.dumps(my_array)
r.set("my_array_as_string", my_array_as_string)

start_time = time.time()
my_array_as_string = r.get("my_array_as_string")
print("Fetch from Redis:", time.time() - start_time)

start_time = time.time()
my_array = json.loads(my_array_as_string)
print("Parse JSON      :", time.time() - start_time)

結果:

JSON from disk  : 1.075700044631958
Fetch from Redis: 0.078125
Parse JSON      : 1.0247752666473389

編輯:似乎從 redis 獲取實際上很快,但 JSON 解析相當慢。 有沒有辦法在沒有 JSON 序列化部分的情況下直接從 Redis 獲取數組? 這就是我們用 pyMySQL 所做的,而且速度很快。

更新:2019 年 11 月 8 日 - 在 Python3.6 上運行相同的測試

結果:

轉儲時間:JSON > msgpack > pickle > marshal
加載時間:JSON > pickle > msgpack > marshal
空間:元帥> JSON>泡菜> msgpack

+---------+-----------+-----------+-------+
| package | dump time | load time | size  |
+---------+-----------+-----------+-------+
| json    | 0.00134   | 0.00079   | 30049 |
| pickle  | 0.00023   | 0.00019   | 20059 |
| msgpack | 0.00031   | 0.00012   | 10036 |
| marshal | 0.00022   | 0.00010   | 50038 |
+---------+-----------+-----------+-------+

我試過pickle vs json vs msgpack vs marshal。

Pickle 比 JSON 慢得多。 msgpack至少比 JSON 快 4 倍。 MsgPack 看起來是您擁有的最佳選擇。

編輯:也試過元帥。 Marshal 比 JSON 快,但比 msgpack 慢。

花費的時間:Pickle > JSON > Marshal > MsgPack
占用空間:Marshal > Pickle > Json > MsgPack

import time
import json
import pickle
import msgpack
import marshal
import sys

array = [1]*10000

start_time = time.time()
json_array = json.dumps(array)
print "JSON dumps: ", time.time() - start_time
print "JSON size: ", sys.getsizeof(json_array)
start_time = time.time()
_ = json.loads(json_array)
print "JSON loads: ", time.time() - start_time

# --------------

start_time = time.time()
pickled_object = pickle.dumps(array)
print "Pickle dumps: ", time.time() - start_time
print "Pickle size: ", sys.getsizeof(pickled_object)
start_time = time.time()
_ = pickle.loads(pickled_object)
print "Pickle loads: ", time.time() - start_time


# --------------

start_time = time.time()
package = msgpack.dumps(array)
print "Msg Pack dumps: ", time.time() - start_time
print "MsgPack size: ", sys.getsizeof(package)
start_time = time.time()
_ = msgpack.loads(package)
print "Msg Pack loads: ", time.time() - start_time

# --------------

start_time = time.time()
m_package = marshal.dumps(array)
print "Marshal dumps: ", time.time() - start_time
print "Marshal size: ", sys.getsizeof(m_package)
start_time = time.time()
_ = marshal.loads(m_package)
print "Marshal loads: ", time.time() - start_time

結果:

    JSON dumps:  0.000760078430176
JSON size:  30037
JSON loads:  0.000488042831421
Pickle dumps:  0.0108790397644
Pickle size:  40043
Pickle loads:  0.0100247859955
Msg Pack dumps:  0.000202894210815
MsgPack size:  10040
Msg Pack loads:  7.58171081543e-05
Marshal dumps:  0.000118017196655
Marshal size:  50042
Marshal loads:  0.000118970870972

一些解釋:

  1. 從磁盤加載數據並不總是意味着磁盤訪問,通常是從內存操作系統緩存返回的數據,當發生這種情況時,這甚至比從 Redis 獲取數據更快(從總時間中刪除網絡通信)

  2. 主要的性能殺手是 JSON 解析(cpt. Obvious)

  3. 從磁盤解析 JSON 很可能與數據加載(來自文件流)並行完成

  4. 沒有使用Redis從流中解析的選項(至少我不知道這樣的API)


只需將緩存文件存儲在tmpfs上,您就可以以最少的更改加速應用程序。 它非常接近同一服務器上的 Redis 設置。

同意@RoopakANelliat msgpack 比 JSON 快大約 4 倍。 格式更改將提高解析性能(如果可能)。

出於這個原因,我專門制作了腦等離子體- 在 Flask 應用程序中快速加載和重新加載大對象。 它是 Apache Arrow 可序列化對象的共享內存對象命名空間,包括pickle.dumps(...)生成的pickle 'd 字節pickle.dumps(...)

$ pip install brain-plasma
$ plasma_store -m 10000000 -s /tmp/plasma # 10MB memory
from brain_plasma import Brain
brain = Brain()

brain['a'] = [1]*10000
brain['a']
# >>> [1,1,1,1,...]

Redis 的 RedisJson 擴展: https ://oss.redislabs.com/redisjson/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM