[dbohdan] 2017-02-03: This benchmark compares the speed with which various [JSON] libraries for Tcl can extract a deeply nested string value from a http://mtgjson.com/%|%large JSON blob%|% (circa 18 MiB). The comparison may help you choose one out of a growing number of similar JSON-parsing libraries for Tcl, but, as any microbenchmark, it has a limited scope. Libraries may be faster or slower under different circumstances. ** How to run the benchmark ** Install cURL (not [TclCurl]), [Git], [jq], Tcl 8.6, [Tcllib] and (optionally) [wiki-reaper]. Install the Tcl extensions [rl_json], SQLite with [JSON1], [tcl-duktape] and [yajl-tcl]. Then run the POSIX shell commands below. ======none mkdir jsonbench cd jsonbench git clone https://github.com/dbohdan/jimhttp # Instead of running the next command you can manually copy the code from the # "Code" section of this wiki page and save it as jsonbench.tcl. wiki-reaper 48500 2 | tee jsonbench.tcl tclsh jsonbench.tcl ====== ** Sample results ** ======none Package versions: Tcllib json -- 1.1.2 duktape -- 0.3.0 jimhttp json -- 2.0.0 rl_json -- 0.9.6 sqlite3 -- 3.16.2 yajltcl -- 1.6.1 Found AllSets.json Running the benchmark with 5 iterations for each library jq: 989.8016 tcl-duktape: 1688.796 jimhttp JSON: 21075.271 rl_json: 87.887 Tcllib JSON: 21810.2016 SQLite JSON1: 61.130199999999995 yajl-tcl: 281.0414 ====== ** Code ** ====== #! /usr/bin/env tclsh # version 0.2.1 package require fileutil puts {Package versions:} puts "Tcllib json -- [package require json]" source jimhttp/json.tcl puts "duktape -- [package require duktape]" package require duktape::oo puts "jimhttp json -- $::json::version" puts "rl_json -- [package require rl_json]" puts "sqlite3 -- [package require sqlite3]" puts "yajltcl -- [package require yajltcl]" puts {} proc ms timeResult { return [expr {[lindex $timeResult 0] / 1000}] } proc benchmark {command data times result} { return [ms [time { set actualResult [$command $data] if {$actualResult ne $result} {error "bad result: \"$actualResult\""} } $times]] } proc jq data { return [exec jq -r {.INV.cards[68].flavor} << $data] } proc duktape data { set j [::duktape::oo::JSON new $::duk $data] set result [$j get INV cards 68 flavor] $j destroy return $result } proc jimhttp-json data { return [dict get [::json::parse $data] INV cards 68 flavor] } proc rl_json data { return [::rl_json::json get $data INV cards 68 flavor] } proc tcllib-json data { return [dict get [lindex [dict get \ [::json::json2dict $data] INV cards] 68] flavor] } proc sqlite3-json1 data { set result [lindex [::sq3 eval { select json_extract($data, '$.INV.cards[68].flavor') }] 0] return $result } proc yajltcl data { return [dict get [lindex [dict get \ [::yajl::json2dict $data] INV cards] 68] flavor] } proc main {} { set times 5 set value {Children claim no two feathers are exactly the same color,\ then eagerly gather them for proof.} if {[file exists AllSets.json]} { puts {Found AllSets.json} } else { puts {The file AllSeet.json doesn't exist} puts {Downloading and extracting AllSets.json.zip...} exec curl -sf -o AllSets.json.zip \ https://mtgjson.com/json/AllSets.json.zip exec unzip AllSets.json.zip file delete AllSets.json.zip puts Done } set sets [::fileutil::cat AllSets.json] puts "Running the benchmark with $times iterations for each library" puts "jq: [benchmark jq $sets $times $value]" set ::duk [::duktape::oo::Duktape new] puts "tcl-duktape: [benchmark duktape $sets $times $value]" $::duk destroy puts "jimhttp JSON: [benchmark tcllib-json $sets $times $value]" puts "rl_json: [benchmark rl_json $sets $times $value]" puts "Tcllib JSON: [benchmark tcllib-json $sets $times $value]" sqlite3 ::sq3 :memory: ::sq3 enable_load_extension 1 puts "SQLite JSON1: [benchmark sqlite3-json1 $sets $times $value]" puts "yajl-tcl: [benchmark yajltcl $sets $times $value]" } main ====== <>Data Serialization Format | Performance