Description
CircuitPython version
Adafruit CircuitPython 8.2.9 on 2023-12-06; FeatherS3 with ESP32S3
Code/REPL
import json
import time
datastr = json.dumps([111, 222, 333, 444, 555] * 10)
# somehow slower than loads_plus_dumps
def loads_alone(datastr):
return json.loads(datastr)
# somehow faster than loads_alone
def loads_plus_dumps(datastr):
json.dumps(None) # adding this line boosts performance!?
return json.loads(datastr)
# test loads
start_ns = time.monotonic_ns()
for i in range(0, 1000):
loads_alone(datastr)
loads_us = (time.monotonic_ns() - start_ns) // (1_000_000)
# test dumps
start_ns = time.monotonic_ns()
for i in range(0, 1000):
loads_plus_dumps(datastr)
dumpsloads_us = (time.monotonic_ns() - start_ns) // (1_000_000)
# report results
print("loads alone: " + str(loads_us) + " us each")
print("dumps + loads: " + str(dumpsloads_us) + " us each")
Behavior
code.py output:
loads alone: 1544 us each
dumps + loads: 424 us each
Description
This feels like a bug, because one would not expect more lines of code to be faster than the same code with lines omitted.
As it is, it seems like there is no reason to ever call json.loads() on it's own - rather, it should always be paired with a json.dumps(None) call first, to boost it's performance..?
Additional information
I tested these functions on Windows Python 3.8 and got the expected result: that loads_alone is faster, on it's own, than loads_plus_dumps - so this issue is specific either to CircuitPython or MicroPython, but does not apply on desktop python.
A possible resolution would be to modify the json module by wrapping the loads func so that it calls json.dumps(None) itself internally? In the meantime, I'm going to make sure to add empty json.dumps(None) calls ahead of any of my json.loads(..) calls to get the performance boost.