简体   繁体   中英

How to deal with TypeError: Object of type 'Thread' is not JSON serializable?

As I mentioned in the title, I'm having trouble setting the Thread object as JSON value. The program gives me TypeError . Here's my code:

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)

This code is waiting for you to enter an input . The input you enter becomes Thread name. Here's the output:

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

As you can see I am getting TypeError: Object of type Thread is not JSON serializable . My expectation from the program is this:

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!
...

How can I deal with this problem? I want to set Thread object as JSON value. Hope you help.

JSON is a very generic way of serializing all sorts of stuff. However, to do that, it uses a technique called "reflection". This will only work with objects that have a known structure, ie in Python it must be a Python object, in C# it must be a C# object.

As soon as you leave the programming language, this generic way of serialization is no longer possible. In this case, a thread is an object that is near the kernel, so it's likely implemented in C or C++ and thus not serializable. The same applies for other stuff that is optimized for performance, eg numpy, which also uses C++ for its implementation.

To deal with that issue, don't serialize the object directly but serialize all information that is needed to re-create the object from scratch again. For numpy, you would convert numbers into Python numbers. For your thread, serialize the name.

My expectation from the program is [...]

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

At the time you first output the serialized object, it has not been started yet, so it cannot have a start time.

At this point you should have noticed that deserializing the thread will not work. If you would deserialize the thread, it would attempt to get the start time, but has not been started yet. And when you start it, it will get a new start time, making the deserialization of the start time useless.

Also, think of the thread ID. If a thread with that ID has already been assigned, you can't simply take it over by deserializing. It will necessarily have a different (like random) thread ID.

I don't know why you'd want to serialize a Thread object, but to do it you need to create a custom JSONEncoder that returns a dictionary representing the serialized object and pass it as the cls parameter to json.dump() or json.dumps() .

To get it back you need an object hook that recognizes the serialized object and regenerates the thread.

This is a very rough example. Note it digs into implementation details of the Thread but this is just for demonstration:

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()

Output:

mythread

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM