【问题标题】:How to deal with TypeError: Object of type 'Thread' is not JSON serializable?如何处理 TypeError:'Thread' 类型的对象不是 JSON 可序列化的?
【发布时间】:2020-08-25 20:42:40
【问题描述】:

正如我在标题中提到的,我无法将 Thread object 设置为 JSON 值。该程序给了我TypeError。这是我的代码:

from threading import Thread
import json
import time

# Set dict
threads = {}

while True:
    
    data = input('What do you want to call your Thread? ')
    
    # Target func
    def targetfunc(name):
        while True:
            print(f"I'm {name} Thread!")
            time.sleep(3)
            
    # Set thread
    threads[data] = Thread(target = targetfunc, args = [data])
    
    # Create threads file
    with open('threads.json', 'w') as rmd:
        json.dump(threads, rmd)

    # Start thread
    threads[data].start()

    # Print inside the dict
    print("INSIDE THE DICT:", threads)

此代码正在等待您输入input。您输入的输入变为Thread 名称。这是输出:

What do you want to call your Thread? love

Traceback (most recent call last):
  File "C:\Users\WINDOWS 8.1\Desktop\MarthaAI\mTest\test3.py", line 23, in <modu
le>
    json.dump(threads, rmd)
  File "C:\Users\WINDOWS 8.1\AppData\Local\Programs\Python\Python37-32\lib\json\
__init__.py", line 179, in dump
    for chunk in iterable:
  File "C:\Users\WINDOWS 8.1\AppData\Local\Programs\Python\Python37-32\lib\json\
encoder.py", line 431, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "C:\Users\WINDOWS 8.1\AppData\Local\Programs\Python\Python37-32\lib\json\
encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "C:\Users\WINDOWS 8.1\AppData\Local\Programs\Python\Python37-32\lib\json\
encoder.py", line 438, in _iterencode
    o = _default(o)
  File "C:\Users\WINDOWS 8.1\AppData\Local\Programs\Python\Python37-32\lib\json\
encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Thread is not JSON serializable

如您所见,我收到了TypeError: Object of type Thread is not JSON serializable。我对这个项目的期望是这样的:

What do you want to call your Thread? love
I'm love Thread!
INSIDE THE DICT: {'love': Thread(Thread-1, started 4060)}
What do you want to call your Thread?
I'm love Thread!
I'm love Thread!
...

我该如何处理这个问题?我想将Thread object 设置为JSON 值。希望对您有所帮助。

【问题讨论】:

  • 您希望它如何工作?错误是完全清楚的 - 你不能将 Thread 对象序列化为 JSON(像这样。我要掩饰我的背后并假设有一些奇怪的方法来做到这一点)。真正的问题是你为什么尝试?
  • # Create threads file 这有什么用?
  • 对于你的第一个问题,我应该停止我必须做的事情,因为它没有序列化吗?对于您的第二个问题,它会创建一个字典并在其中保留 Thread namevalue
  • 没有停止Thread的功能,但我使用flag来停止它。请不要告诉我没有办法,因为总有办法做某事..
  • @roganjosh:可以序列化几乎所有内容。为什么不用线程?

标签: python arrays json multithreading dictionary


【解决方案1】:

JSON 是一种非常通用的序列化各种东西的方式。但是,为此,它使用了一种称为“反射”的技术。这仅适用于具有已知结构的对象,即在 Python 中它必须是 Python 对象,在 C# 中它必须是 C# 对象。

一旦离开编程语言,这种通用的序列化方式就不再可能了。在这种情况下,线程是靠近内核的对象,因此它可能是用 C 或 C++ 实现的,因此不可序列化。这同样适用于针对性能优化的其他东西,例如numpy,它也使用 C++ 来实现。

为了解决这个问题,不要直接序列化对象,而是序列化重新从头开始重新创建对象所需的所有信息。对于 numpy,您可以将数字转换为 Python 数字。对于您的线程,序列化名称。

我对该计划的期望是 [...]

INSIDE THE DICT: {'love': Thread(Thread-1, started 4060)}

在你第一次输出序列化对象的时候,它还没有启动,所以它不能有启动时间。

此时您应该已经注意到反序列化线程将不起作用。如果您要反序列化线程,它将尝试获取开始时间,但尚未开始。而当你启动它时,它会得到一个新的开始时间,使得开始时间的反序列化无用。

另外,想想线程 ID。如果已经分配了具有该 ID 的线程,则不能简单地通过反序列化来接管它。它必然有不同的(比如随机的)线程 ID。

【讨论】:

  • 即便如此,您也必须为 python 对象编写自定义序列化程序。 json 模块不会为你做这件事 - pickle 可以解决这个问题,但会带来一些问题。我不觉得这回答了这个问题。您回答“可以完成”而不是“如何处理 TypeError:'Thread' 类型的对象不是 JSON 可序列化的?”,这是实际问题
  • 嗯,“前进的道路”还是很清楚的。 pickle 可以处理 数据的序列化要求, 但它无法知道接收该数据的对象。因此,底层对象将需要具有“保存”和“恢复”方法,这些方法首先知道如何生产然后消费这样的“泡菜”。 // (我会提醒询问者,“github.com”和这样的地方已经提供了大量现成的编码示例!“不要做已经做过的事情!”)
【解决方案2】:

我不知道您为什么要序列化一个 Thread 对象,但要做到这一点,您需要创建一个自定义 JSONEncoder,它返回一个表示序列化对象的字典并将其作为 cls 参数传递给json.dump()json.dumps()

要取回它,您需要一个对象挂钩来识别序列化对象并重新生成线程。

这是一个非常粗略的例子。请注意,它深入探讨了 Thread 的实现细节,但这只是为了演示:

import json
import threading
import pickle

class ThreadEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, threading.Thread):
            # serialize the function and arguments used by the thread.
            # the result must be a JSON-serializable object, in this case a "str".
            f = pickle.dumps(obj._target).decode('latin1')
            a = pickle.dumps(obj._args).decode('latin1')
            # return a JSON-serializable dictionary representing a Thread
            return {'thread':f, 'args': a}
        # Let the base class default method raise a TypeError for unsupported objects.
        return json.JSONEncoder.default(self, obj)

# This object hook recognizes a Thread object dictionary created by ThreadEncoder,
# retrieves the function and arguments, and creates a Thread object.
# Note this isn't a perfect reproduction of the Thread object...it doesn't restore other
# possible parameters to the constructor like "daemon" or "name".
def as_thread(dct):
    # assume a 'thread' key indicates a Thread dictionary object.
    if 'thread' in dct:
        f = pickle.loads(dct['thread'].encode('latin1'))
        a = pickle.loads(dct['args'].encode('latin1'))
        return threading.Thread(target=f, args=a)
    return dct # return unchanged if not a Thread.

def func(name):
    print(name)

name = 'mythread'
t = threading.Thread(target=func,args=(name,))

s = json.dumps(t,cls=ThreadEncoder) # serialize thread

del t  # destroy the object

j = json.loads(s,object_hook=as_thread) # restore the object

j.start() # run it.
j.join()

输出:

mythread

【讨论】:

    猜你喜欢
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 2019-11-21
    • 2021-11-13
    • 2018-09-22
    • 2019-01-17
    • 2019-12-07
    相关资源
    最近更新 更多