多线程环境和模块,如pickle或json

时间:2014-05-20 07:58:29

标签: python json multithreading pickle

我正在使用“import threading”和python 3.4。 简单的情况下,我有一个主要父线程和一个子线程。我需要将我的dict保存到子线程的文件中。在线程函数中我有变量:

def thread_function(...)
    def save_to_file():
        this_thread_data.my_dict or nonlocal this_thread_data.my_dict 
        ... json or pickle


    this_thread_data = local()
    this_thread_data.my_dict = {...}
    ...

当我使用泡菜时,我收到错误

_pickle.PicklingError: Can't pickle <class '_thread.lock'>: attribute lookup lock on _thread failed

当我使用json时,我收到错误

TypeError: <threading.Event object at 0x7f49115a9588> is not JSON serializable

pickle或json是否会在多线程环境中工作,或者我需要使用别的东西?

谢谢。

3 个答案:

答案 0 :(得分:3)

除非你跳到标准库之外,否则Python线程(和多处理)和pickle都会被破坏和限制。

如果使用名为multiprocessing的{​​{1}}的分支,则可以在多处理的pathos.multiprocesssing函数中直接使用类和类方法。这是因为map代替dillpicklecPickle可以序列化python中的几乎任何内容。 dill提供了一个与线程模块的接口,就像标准的python模块一样。

pathos.multiprocessing还提供异步映射函数......它可以pathos.multiprocessing具有多个参数的函数(例如map

请参阅: What can multiprocessing and dill do together?

和: http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization/

map(math.pow, [1,2,3], [4,5,6])

在词典中有不寻常的东西,无所谓......

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> #from pathos.multiprocessing import ThreadingPool as Pool
>>> 
>>> p = Pool(4)
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> x = [0,1,2,3]
>>> y = [4,5,6,7]
>>> 
>>> p.map(add, x, y)
[4, 6, 8, 10]
>>> 
>>> class Test(object):
...   def plus(self, x, y): 
...     return x+y
... 
>>> t = Test()
>>> 
>>> p.map(Test.plus, [t]*4, x, y)
[4, 6, 8, 10]
>>> 
>>> p.map(t.plus, x, y)
[4, 6, 8, 10]

顺便说一下,如果你想挑选一个线程锁,你也可以这样做。

>>> d = {'1':add, '2':t, '3':Test, '4':range(10), '5':1}
>>>                        
>>> def items(x):
...   return x[0],x[1]
... 
>>> p.map(items, d.items())
[('1', <function add at 0x103b7e2a8>), ('3', <class '__main__.Test'>), ('2', <__main__.Test object at 0x103b7ad90>), ('5', 1), ('4', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])]

看起来你想要构建某种类型的闭包,它会自动将函数调用存储到文件或至少存储到序列化字符串。如果那是你想要的, 你可以尝试>>> import dill as pickle >>> import threading >>> lock = threading.Lock() >>> >>> pickle.loads(pickle.dumps(lock)) <thread.lock object at 0x10c534650> ,它会为你提供一个你应用于你的函数的装饰器 你得缓存到内存或磁盘或数据库。 klepto可以使用pickle或json, 但它增加了Klepto,所以它可以在python中序列化几乎任何东西 - 所以不要 担心你的词汇中有什么......只是序列化它。

dill

from klepto import lru_cache as memoize from klepto.keymaps import picklemap dumps = picklemap(serializer='dill') class Adder(object): """A simple class with a memoized method""" @memoize(keymap=dumps, ignore=('self','**')) def __call__(self, x, *args, **kwds): debug = kwds.get('debug', False) if debug: print ('debug:', x, args, kwds) return sum((x,)+args) add = __call__ add = Adder() assert add(2,0) == 2 assert add(2,0,z=4) == 2 # cached (ignore z) assert add(2,0,debug=False) == 2 # cached (ignore debug) assert add(1,2,debug=False) == 3 assert add(1,2,debug=True) == 3 # cached (ignore debug) assert add(4) == 4 assert add(x=4) == 4 # cached 可让您在重新启动代码时获得所有缓存结果。 在这种情况下,您选择一些文件或数据库后端,然后确保对存档执行Klepto ...然后重新启动python或其他任何内容,并执行add.dump()以加载存档的结果。

在此处获取代码:  https://github.com/uqfoundation

答案 1 :(得分:1)

使用pickle和json可以在多线程环境中正常工作(但可能不是线程安全的,因此请确保您正在进行酸洗的数据当时不能更改,例如使用锁定)。问题在于,您将被限制为可以实际保存到磁盘的数据类型。

并非所有对象都是可序列化的,正如您所发现的那样。最简单的方法是确保您的字典只具有与pickle或json序列化程序兼容的值。例如,您似乎在字典中存储了一个锁定对象,使得pickle失败。您可能想要创建一个只包含可以腌制的值的新字典,然后将其腌制。

或者,如果您想创建一个自定义对象来存储您的数据,您可以告诉pickle如何挑选它。这是更高级的,在您的情况下可能没有必要,但您可以在此处找到更多文档:https://docs.python.org/3.4/library/pickle.html#pickling-class-instances

答案 2 :(得分:0)

有更好的方法在线程之间共享数据。如果您愿意使用进程而不是线程,我建议使用python'multiprocessing'模块,特别是'Manager'类:https://docs.python.org/2/library/multiprocessing.html#managers。这是一个玩具示例:

from multiprocessing import Manager, Process

def on_separate_process(alist):
   print alist

manager = Manager()
alist = manager.list([1,2,3])

p = Process(target=on_separate_process, args=[alist])
p.start()

打印[1,2,3]