我正在使用“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是否会在多线程环境中工作,或者我需要使用别的东西?
谢谢。
答案 0 :(得分:3)
如果使用名为multiprocessing
的{{1}}的分支,则可以在多处理的pathos.multiprocesssing
函数中直接使用类和类方法。这是因为map
代替dill
或pickle
,cPickle
可以序列化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]