view julia/parallel/ParallelProcessing/src/json.jl @ 35:8208faa6c42f

JSON: Better struct coding
author Lewin Bormann <lbo@spheniscida.de>
date Fri, 24 Mar 2023 20:04:38 +0100
parents 2d033830c26e
children 03d20a4dd8f2
line wrap: on
line source

using JSON
using Random
import Base.Threads

struct Details
    level::String
    kind::Int
end

"""Example for a method that can be derived straight from a struct definition and parses just a struct
            from a JSON object."""
function take_struct!(::Type{Details}, jp::JP)::Union{Nothing,Details}
    expect!(jp, '{') || return nothing

    level::Union{Nothing,String} = nothing
    kind::Union{Nothing, Int} = nothing
    while true
        key = take_str!(jp)
        if isnothing(key)
            break
        end

        expect!(jp, ':') || error("malformed object - expected ':'")

        # Custom code!
        if key == "level"
            level = take_str!(jp)
        elseif key == "kind"
            kind = take_num!(jp)
        else
            # Ignore unknown keys
            take_val!(jp)
        end

        if expect!(jp, ',')
            continue
        else
            break
        end
    end

    if isnothing(level) || isnothing(kind)
        error("Elements missing from object: $level, $kind")
    end

    expect!(jp, '}') || error("unclosed Details object")
    
    Details(level, kind)
end

struct SimpleEntry
    s::String
    a::Int
    f::Float64
    details::Details
end

function generate_entry()::SimpleEntry
    s, level = randstring(20), randstring(10)
    a, kind = rand(Int, 2)
    f = rand()
    SimpleEntry(s, a, f, Details(level, kind))
end

function generate_json(file, n=1000)
    open(file; write=true) do fh
        for i = 1:n
            println(fh, json(generate_entry()))
        end
    end
end

fib(n) = if n <= 2 1 else fib(n-1) + fib(n-2) end

function expensive_mapper(m::Dict)::Int
    i = abs(m["a"]) % 35
    fib(i)
end

function process_json(file, mapper=x -> ())::Vector
    open(file; read=true) do fh
        [mapper(JSON.parse(line)) for line = eachline(fh)]
    end
end


function process_json_parallel(file, mapper=x -> ())::Vector
    open(file; read=true) do fh
        ch = Channel(100)
        count = 0
        for line = eachline(fh)
            Threads.@spawn put!(ch, mapper(JSON.parse(line)))
            count += 1
        end
        [take!(ch) for i = 1:count]
    end
end