5

我有一组数据点,每个数据点都由字典描述。每个数据点的处理都是独立的,我将每个数据点作为单独的作业提交给集群。每个数据点都有一个唯一的名称,我的集群提交包装器只需调用一个脚本,该脚本采用数据点的名称和描述所有数据点的文件。然后该脚本访问文件中的数据点并执行计算。

由于每个作业都必须加载所有点的集合以检索要运行的点,因此我想通过将描述点集的文件序列化为易于检索的格式来优化此步骤。

我尝试使用 JSONpickle,使用以下方法,将描述所有数据点的字典序列化到文件:

def json_serialize(obj, filename, use_jsonpickle=True):
    f = open(filename, 'w')
    if use_jsonpickle:
    import jsonpickle
    json_obj = jsonpickle.encode(obj)
    f.write(json_obj)
    else:
    simplejson.dump(obj, f, indent=1)   
    f.close()

该字典包含非常简单的对象(列表、字符串、浮点数等),总共有 54,000 个键。json 文件的大小约为 20 兆字节。

将此文件加载到内存中大约需要 20 秒,这对我来说似乎很慢。我切换到使用具有相同对象的 pickle,发现它生成了一个大小约为 7.8 MB 的文件,并且可以在大约 1-2 秒内加载。这是一个显着的改进,但看起来加载一个小对象(少于 100,000 个条目)应该更快。除此之外,pickle 不是人类可读的,这对我来说是 JSON 的一大优势。

有没有办法使用 JSON 来获得类似或更好的加速?如果没有,您对构建它有其他想法吗?

(将描述每个事件的文件简单地“切片”成一个单独的文件并将其传递给在集群作业中运行数据点的脚本是正确的解决方案吗?这似乎可能导致文件激增)。

谢谢。

4

2 回答 2

7

marshal是最快的,但pickle本身不是 - 也许你的意思是cPickle(这非常快,尤其是使用-1协议)。所以,除了可读性问题,这里有一些代码来展示各种可能性:

import pickle
import cPickle
import marshal
import json

def maked(N=5400):
  d = {}
  for x in range(N):
    k = 'key%d' % x
    v = [x] * 5
    d[k] = v
  return d
d = maked()

def marsh():
  return marshal.dumps(d)

def pick():
  return pickle.dumps(d)

def pick1():
  return pickle.dumps(d, -1)

def cpick():
  return cPickle.dumps(d)

def cpick1():
  return cPickle.dumps(d, -1)

def jso():
  return json.dumps(d)

def rep():
  return repr(d)

这是他们在我的笔记本电脑上的速度:

$ py26 -mtimeit -s'import pik' 'pik.marsh()'
1000 loops, best of 3: 1.56 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.pick()'
10 loops, best of 3: 173 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.pick1()'
10 loops, best of 3: 241 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.cpick()'
10 loops, best of 3: 21.8 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.cpick1()'
100 loops, best of 3: 10 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.jso()'
10 loops, best of 3: 138 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.rep()'
100 loops, best of 3: 13.1 msec per loop

因此,您可以获得可读性十倍于json.dumpswith的速度repr(您牺牲了从 Javascript 和其他语言解析的便利性);您可以拥有绝对最大速度marshal,几乎比 ; 快 90 倍json;提供了比orcPickle更多的通用性(就您可以序列化的内容而言),但如果您永远不会使用这种通用性,那么您不妨选择(或者如果人类可读性胜过速度)。jsonmarshalmarshalrepr

至于您的“切片”想法,代替大量文件,您可能需要考虑一个数据库(大量记录)——如果您正在使用具有一些可识别的数据运行,您甚至可能在没有实际序列化的情况下逃脱“模式”。

于 2010-04-20T02:00:50.497 回答
1

我认为您在这里面临权衡:人类可读性是以性能和大文件大小为代价的。因此,在 Python 中可用的所有序列化方法中,JSON 不仅可读性最强,而且速度最慢。

如果我必须追求性能(和文件紧凑性),我会选择marshall。您可以使用dump()load()对整个数据集进行编组,或者根据您对事物进行切片的想法,将数据集的单独部分编组到单独的文件中。这样,您就为数据处理的并行化打开了大门——如果您愿意的话。

当然,文档中有各种限制和警告,所以如果你决定安全起见,那就去pickle

于 2010-04-20T01:40:57.123 回答