所以我有一个字典,它是我从Redis获取的哈希对象,类似于以下字典:
source_data = {
b'key-1': b'{"age":33,"gender":"Male"}',
b'key-2': b'{"age":20,"gender":"Female"}'
}
我的目标是从此字典中提取所有值,并将其作为Python字典的列表,如下所示:
final_data = [
{
'age': 33,
'gender': 'Male'
},
{
'age': 20,
'gender': 'Female'
}
]
我尝试了使用json解析的列表理解:
import json
final_data = [json.loads(a) for a in source_data.values()]
它可以工作,但对于大型数据集,则需要太多时间。
我转而使用此第三方json模块ujson,根据此benchmark,该模块速度更快,但我没有发现任何改进。
我尝试使用多线程:
pool = Pool()
final_data = pool.map(ujson.loads, source_data.values(), chunksize=500)
pool.close()
pool.join()
我在chunksize
上玩了一点,但是结果是一样的,仍然花费太多时间。
如果有人可以提出其他解决方案或对以前的尝试进行改进,那将非常有帮助,如果我可以避免使用循环,那将是理想的选择。
答案 0 :(得分:4)
假设值确实是有效的JSON,则构建单个 JSON对象进行解码可能会更快。我认为将这些值连接到单个字符串中应该是安全的。
using UnityEngine;
using System.Collections;
using MySql.Data.MySqlClient;
using System;
using System.Linq;
using System.Collections.Generic;
public class MySqlTestScript : MonoBehaviour
{
private static MySqlTestScript _instnace;
public static MySqlTestScript sharedInstance()
{
return _instnace;
}
string row = "";
public string host = "*****";
public string database = "*******";
public string usrename= "*******";
public string password = "******";
public List<Data> userData = new List<Data>();
Data data;
void Awake()
{
_instnace = this;
}
// Use this for initialization
public void Start()
{
GetDataFromDatabase();
}
public string GetDataFromDatabase()
{
string myConnectionString = "Server="+host+";Database="+database+";Uid="+usrename+ ";Pwd="+password+";";
MySqlConnection connection = new MySqlConnection(myConnectionString);
MySqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Users";
MySqlDataReader Reader;
try
{
connection.Open();
Reader = command.ExecuteReader();
while (Reader.Read())
{
for (int i = 0; i < Reader.FieldCount; i++)
{
//rfid_tags.Add (Reader.GetString("UserName"));
//rfid_tags.Add(Reader.GetString("RFID_Tag"));
data = new Data(Reader.GetString("UserName"), Reader.GetString("RFID_Tag"));
userData.Add(data);
// ws.DomainUrl = reader.GetString("DomainUrl");
// rfid_tags.Add(Reader.GetValue(i).ToString() + ",");
// row += Reader.GetValue(i).ToString() + ", ";
}
Debug.Log(row);
}
}
catch (Exception x)
{
Debug.Log(x.Message);
return x.Message;
}
connection.Close();
return row;
}
}
public class Data {
public string username { get; set; }
public string rfid { get; set; }
public Data(string _name, string _rfid)
{
username = _name;
rfid = _rfid;
}
public void SetUserName(string _userName) { username = _userName; }
public void SetRFID(string _rfid) { rfid = _rfid; }
}
用一次调用void OnTagsReported(ImpinjReader sender, TagReport report)
{
Debug.Log("OnTagsReported");
// This event handler is called asynchronously
// when tag reports are available.
// Loop through each tag in the report
// and print the data.
foreach (Tag tag in report)
{
Debug.Log(tag.Epc);
// Debug.Log(MySqlTestScript.sharedInstance().rfid_tags[0]);
Debug.Log("STEP ONE");
for (int i = 0; i < MySqlTestScript.sharedInstance().userData.Count; i++)
{
Debug.Log("STEP TWO");
if (tag.Epc.ToString().Trim() == MySqlTestScript.sharedInstance().userData[i].rfid)
{
Debug.Log("STEP THREE");
// TODO References the Name
Loom.QueueOnMainThread(() => {
namesTxt[i].text = MySqlTestScript.sharedInstance().userData[i].username;
});
}
}
和一次字符串格式化操作的较小开销,代替了调用>>> new_json = b'[%s]' % (b','.join(source_data.values(),)
>>> new_json
b'[{"age":33,"gender":"Male"},{"age":20,"gender":"Female"}]'
>>> json.loads(new_json)
[{'age': 33, 'gender': 'Male'}, {'age': 20, 'gender': 'Female'}]
2000次以上的开销。
答案 1 :(得分:1)
作为参考,我尝试复制这种情况:
import json, timeit, random
source_data = { 'key-{}'.format(n).encode('ascii'):
'{{"age":{},"gender":"{}"}}'.format(
random.randint(18,75),
random.choice(("Male", "Female"))
).encode('ascii')
for n in range(45000) }
timeit.timeit("{ k: json.loads(v) for (k,v) in source_data.items() }",
number=1, globals={'json': json, 'source_data': source_data})
此过程在不到一秒钟的时间内完成。那超过30秒的时间一定是我看不见的。
我最接近的猜测是,您将数据保存在某种代理容器中,其中每个密钥提取都变成了远程调用,例如使用hscan
而不是hgetall
。使用count
的{{1}}提示可以在两者之间进行权衡。
正确的性能分析应揭示延迟的来源。