At a glance, why don't I have better performances between Julia and PHP?

Mmmm, i obtain this … Do you understand something?

The output is more than 1500 lines and discourse here do not permit post of this entity, so i copy/paste only the portion of profile output that contain cross and crossdo that are the 2 functions surely slow (becase the @time macro showed me this).

  ╎    68  c:\prg\julia\robot6.jl:86; cross(::Array{SubString{String...
   ╎     2   c:\prg\julia\robot6.jl:52; crossdo(::SubString{String}, :...
   ╎    ╎ 2   @Base\operators.jl:294; >
   ╎    ╎  2   @Base\operators.jl:268; <
   ╎    ╎   2   ...\strings\basic.jl:315; isless
  1╎    ╎    1   ...\strings\basic.jl:271; cmp(::String, ::SubString{S...
   ╎    ╎    1   ...\strings\basic.jl:272; cmp(::String, ::SubString{S...
   ╎    ╎     1   @Base\iterators.jl:1213; Stateful
   ╎    ╎    ╎ 1   ...ngs\substring.jl:70; iterate
   ╎    ╎    ╎  1   ...ngs\substring.jl:70; iterate
  1╎    ╎    ╎   1   @Base\int.jl:53; +
   ╎     48  c:\prg\julia\robot6.jl:53; crossdo(::SubString{String}, :...
   ╎    ╎ 48  @Base\strings\util.jl:313; split
   ╎    ╎  48  ...e\strings\util.jl:313; #split#326
   ╎    ╎   1   @Base\array.jl:394; getindex
   ╎    ╎    1   @Base\boot.jl:424; Array
  1╎    ╎     1   @Base\boot.jl:405; Array
  1╎    ╎   1   ...e\strings\util.jl:0; _split(::SubString{String},...
   ╎    ╎   3   ...e\strings\util.jl:327; _split(::SubString{String},...
   ╎    ╎    3   ...strings\search.jl:104; findfirst
   ╎    ╎     3   ...trings\search.jl:275; findnext
   ╎    ╎    ╎ 3   ...trings\search.jl:239; _search
   ╎    ╎    ╎  2   ...rings\search.jl:150; _searchindex(::SubString{...
   ╎    ╎    ╎   2   ...rings\search.jl:133; findnext(::Base.Fix2{typ...
   ╎    ╎    ╎    2   @Base\generator.jl:44; iterate
   ╎    ╎    ╎     2   ...e\iterators.jl:334; iterate
   ╎    ╎    ╎    ╎ 2   ...e\iterators.jl:343; _zip_iterate_all
   ╎    ╎    ╎    ╎  1   ...\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    ╎   1   ...ings\basic.jl:540; iterate
   ╎    ╎    ╎    ╎    1   ...\substring.jl:96; nextind
  1╎    ╎    ╎    ╎     1   ...gs\string.jl:145; _nextind_str(::SubSt...
   ╎    ╎    ╎    ╎  1   ...\iterators.jl:353; _zip_iterate_some
   ╎    ╎    ╎    ╎   1   ...\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    ╎    1   ...\substring.jl:72; iterate
   ╎    ╎    ╎    ╎     1   ...gs\string.jl:183; iterate
  1╎    ╎    ╎    ╎    ╎ 1   @Base\int.jl:53; +
  1╎    ╎    ╎  1   ...rings\search.jl:154; _searchindex(::SubString{...
   ╎    ╎   8   ...e\strings\util.jl:333; _split(::SubString{String},...
   ╎    ╎    4   @Base\array.jl:914; push!
  4╎    ╎     4   @Base\array.jl:871; _growend!
   ╎    ╎    1   ...\strings\basic.jl:457; prevind
   ╎    ╎     1   ...strings\basic.jl:465; prevind(::SubString{String...
   ╎    ╎    ╎ 1   ...ngs\substring.jl:86; isvalid
   ╎    ╎    ╎  1   ...rings\string.jl:299; isvalid(::String, ::Int64)
   ╎    ╎    ╎   1   ...trings\basic.jl:186; checkbounds
  1╎    ╎    ╎    1   @Base\int.jl:410; <=
   ╎    ╎    3   ...ings\substring.jl:44; SubString
   ╎    ╎     3   ...ings\substring.jl:38; SubString
  1╎    ╎    ╎ 1   ...ngs\substring.jl:0; SubString
   ╎    ╎    ╎ 2   ...ngs\substring.jl:34; SubString
   ╎    ╎    ╎  2   ...rings\string.jl:137; nextind
  2╎    ╎    ╎   2   ...rings\string.jl:145; _nextind_str(::String, :...
   ╎    ╎   34  ...e\strings\util.jl:338; _split(::SubString{String},...
   ╎    ╎    34  ...strings\search.jl:275; findnext
   ╎    ╎     33  ...trings\search.jl:239; _search
  2╎    ╎    ╎ 2   ...trings\search.jl:144; _searchindex(::SubString{...
   ╎    ╎    ╎ 7   ...trings\search.jl:148; _searchindex(::SubString{...
   ╎    ╎    ╎  7   @Base\iterators.jl:544; peel
   ╎    ╎    ╎   7   @Base\iterators.jl:518; rest
   ╎    ╎    ╎    7   @Base\iterators.jl:500; Rest
  7╎    ╎    ╎     7   ...e\iterators.jl:500; Rest
   ╎    ╎    ╎ 10  ...trings\search.jl:150; _searchindex(::SubString{...
  1╎    ╎    ╎  1   ...rings\search.jl:0; findnext(::Base.Fix2{type...
  1╎    ╎    ╎  1   ...rings\search.jl:128; findnext(::Base.Fix2{type...
   ╎    ╎    ╎  6   ...rings\search.jl:131; findnext(::Base.Fix2{type...
   ╎    ╎    ╎   1   @Base\generator.jl:44; iterate
   ╎    ╎    ╎    1   @Base\iterators.jl:333; iterate
   ╎    ╎    ╎     1   ...e\iterators.jl:343; _zip_iterate_all
   ╎    ╎    ╎    ╎ 1   ...e\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    ╎  1   ...ings\basic.jl:540; iterate
   ╎    ╎    ╎    ╎   1   ...ings\basic.jl:540; iterate
   ╎    ╎    ╎    ╎    1   ...\substring.jl:96; nextind
  1╎    ╎    ╎    ╎     1   ...gs\string.jl:141; _nextind_str(::SubSt...
   ╎    ╎    ╎   5   ...gs\substring.jl:39; SubString
   ╎    ╎    ╎    5   ...gs\substring.jl:44; SubString
   ╎    ╎    ╎     5   ...gs\substring.jl:38; SubString
  2╎    ╎    ╎    ╎ 5   ...s\substring.jl:34; SubString
   ╎    ╎    ╎    ╎  3   ...ngs\string.jl:137; nextind
  2╎    ╎    ╎    ╎   2   ...ngs\string.jl:141; _nextind_str(::String...
  1╎    ╎    ╎    ╎   1   ...ngs\string.jl:145; _nextind_str(::String...
   ╎    ╎    ╎  2   ...rings\search.jl:133; findnext(::Base.Fix2{type...
   ╎    ╎    ╎   2   @Base\generator.jl:44; iterate
   ╎    ╎    ╎    2   @Base\iterators.jl:334; iterate
   ╎    ╎    ╎     2   ...e\iterators.jl:343; _zip_iterate_all
   ╎    ╎    ╎    ╎ 2   ...e\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    ╎  2   ...ings\basic.jl:540; iterate
   ╎    ╎    ╎    ╎   2   ...\substring.jl:96; nextind
  2╎    ╎    ╎    ╎    2   ...ngs\string.jl:141; _nextind_str(::SubStr...
   ╎    ╎    ╎ 3   ...trings\search.jl:152; _searchindex(::SubString{...
   ╎    ╎    ╎  3   ...ngs\substring.jl:96; nextind
  1╎    ╎    ╎   2   ...rings\string.jl:141; _nextind_str(::SubString...
  1╎    ╎    ╎    1   @Base\promotion.jl:398; ==
   ╎    ╎    ╎   1   ...rings\string.jl:145; _nextind_str(::SubString...
  1╎    ╎    ╎    1   @Base\int.jl:53; +
   ╎    ╎    ╎ 8   ...trings\search.jl:153; _searchindex(::SubString{...
  8╎    ╎    ╎  8   @Base\iterators.jl:1213; Stateful
   ╎    ╎    ╎ 3   ...trings\search.jl:154; _searchindex(::SubString{...
   ╎    ╎    ╎  1   @Base\reduce.jl:815; all
   ╎    ╎    ╎   1   @Base\reduce.jl:819; _all(::Base.var"#68#69"{...
   ╎    ╎    ╎    1   @Base\iterators.jl:333; iterate
   ╎    ╎    ╎     1   ...e\iterators.jl:341; _zip_iterate_all
   ╎    ╎    ╎    ╎ 1   ...e\iterators.jl:373; _zip_isdone
  1╎    ╎    ╎    ╎  1   ...essentials.jl:205; tail
   ╎    ╎    ╎  2   ...gs\substring.jl:39; SubString
   ╎    ╎    ╎   1   ...trings\basic.jl:159; lastindex
  1╎    ╎    ╎    1   ...gs\substring.jl:95; thisind(::SubString{Stri...
   ╎    ╎    ╎   1   ...gs\substring.jl:44; SubString
   ╎    ╎    ╎    1   ...gs\substring.jl:38; SubString
  1╎    ╎    ╎     1   ...gs\substring.jl:34; SubString
  1╎    ╎     1   ...trings\search.jl:240; _search
   ╎    ╎   1   ...e\strings\util.jl:344; _split(::SubString{String},...
   ╎    ╎    1   @Base\array.jl:914; push!
  1╎    ╎     1   @Base\array.jl:871; _growend!
   ╎     2   c:\prg\julia\robot6.jl:56; crossdo(::SubString{String}, :...
   ╎    ╎ 2   @Base\dict.jl:545; haskey
   ╎    ╎  2   @Base\dict.jl:289; ht_keyindex(::Dict{String,St...
   ╎    ╎   2   @Base\operators.jl:123; isequal
   ╎    ╎    2   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:273; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\iterators.jl:333; iterate
   ╎    ╎    ╎  1   @Base\iterators.jl:345; _zip_iterate_all
   ╎    ╎    ╎   1   @Base\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    1   ...e\iterators.jl:1263; iterate
   ╎    ╎    ╎     1   ...e\iterators.jl:1263; iterate
   ╎    ╎    ╎    ╎ 1   ...\iterators.jl:1256; popfirst!
   ╎    ╎    ╎    ╎  1   ...s\substring.jl:72; iterate
   ╎    ╎    ╎    ╎   1   ...ngs\string.jl:183; iterate
  1╎    ╎    ╎    ╎    1   @Base\int.jl:53; +
  1╎    ╎     1   ...strings\basic.jl:276; cmp(::SubString{String}, :...
   ╎     1   c:\prg\julia\robot6.jl:57; crossdo(::SubString{String}, :...
   ╎    ╎ 1   @Base\dict.jl:476; getindex
   ╎    ╎  1   @Base\dict.jl:289; ht_keyindex(::Dict{String,St...
   ╎    ╎   1   @Base\operators.jl:123; isequal
   ╎    ╎    1   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:274; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\operators.jl:193; !=
   ╎    ╎    ╎  1   @Base\char.jl:208; ==
  1╎    ╎    ╎   1   @Base\promotion.jl:398; ==
   ╎     2   c:\prg\julia\robot6.jl:58; crossdo(::SubString{String}, :...
   ╎    ╎ 2   @Base\array.jl:130; vect
   ╎    ╎  2   @Base\array.jl:657; _array_for
   ╎    ╎   2   ...\abstractarray.jl:670; similar
   ╎    ╎    2   ...\abstractarray.jl:671; similar
   ╎    ╎     2   @Base\boot.jl:414; Array
  2╎    ╎    ╎ 2   @Base\boot.jl:405; Array
   ╎     3   c:\prg\julia\robot6.jl:60; crossdo(::SubString{String}, :...
   ╎    ╎ 3   @Base\dict.jl:545; haskey
   ╎    ╎  1   @Base\dict.jl:282; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   1   @Base\dict.jl:168; hashindex
   ╎    ╎    1   @Base\hashing.jl:18; hash
  1╎    ╎     1   @Base\hashing2.jl:179; hash
   ╎    ╎  2   @Base\dict.jl:289; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   2   @Base\operators.jl:123; isequal
   ╎    ╎    2   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:272; cmp(::SubString{String}, :...
  1╎    ╎    ╎ 1   @Base\iterators.jl:1213; Stateful
   ╎    ╎     1   ...strings\basic.jl:274; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\iterators.jl:334; iterate
   ╎    ╎    ╎  1   @Base\iterators.jl:345; _zip_iterate_all
   ╎    ╎    ╎   1   @Base\iterators.jl:353; _zip_iterate_some
   ╎    ╎    ╎    1   @Base\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎     1   ...e\iterators.jl:1263; iterate
  1╎    ╎    ╎    ╎ 1   ...\iterators.jl:1256; popfirst!
   ╎     3   c:\prg\julia\robot6.jl:61; crossdo(::SubString{String}, :...
   ╎    ╎ 1   @Base\dict.jl:476; getindex
   ╎    ╎  1   @Base\dict.jl:289; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   1   @Base\operators.jl:123; isequal
   ╎    ╎    1   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:272; cmp(::SubString{String}, :...
  1╎    ╎    ╎ 1   @Base\iterators.jl:1213; Stateful
   ╎    ╎ 2   @Base\tuple.jl:82; indexed_iterate
  2╎    ╎  2   @Base\tuple.jl:82; indexed_iterate
   ╎     1   c:\prg\julia\robot6.jl:63; crossdo(::SubString{String}, :...
   ╎    ╎ 1   @Base\dict.jl:376; setindex!(::Dict{String,Arra...
   ╎    ╎  1   @Base\dict.jl:381; setindex!(::Dict{String,Arra...
   ╎    ╎   1   @Base\dict.jl:348; ht_keyindex2!(::Dict{String...
   ╎    ╎    1   @Base\dict.jl:191; rehash!(::Dict{String,Array...
   ╎    ╎     1   @Base\array.jl:500; zeros
   ╎    ╎    ╎ 1   @Base\array.jl:504; zeros
   ╎    ╎    ╎  1   @Base\boot.jl:414; Array
  1╎    ╎    ╎   1   @Base\boot.jl:405; Array
   ╎     2   c:\prg\julia\robot6.jl:72; crossdo(::SubString{String}, :...
   ╎    ╎ 2   @Base\dict.jl:476; getindex
   ╎    ╎  2   @Base\dict.jl:289; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   2   @Base\operators.jl:123; isequal
   ╎    ╎    2   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:272; cmp(::SubString{String}, :...
  1╎    ╎    ╎ 1   @Base\iterators.jl:1213; Stateful
   ╎    ╎     1   ...strings\basic.jl:274; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\iterators.jl:334; iterate
   ╎    ╎    ╎  1   @Base\iterators.jl:345; _zip_iterate_all
   ╎    ╎    ╎   1   @Base\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    1   ...e\iterators.jl:1263; iterate
   ╎    ╎    ╎     1   ...e\iterators.jl:1256; popfirst!
   ╎    ╎    ╎    ╎ 1   ...s\substring.jl:70; iterate
  1╎    ╎    ╎    ╎  1   @Base\int.jl:53; +
   ╎     1   c:\prg\julia\robot6.jl:73; crossdo(::SubString{String}, :...
   ╎    ╎ 1   @Base\dict.jl:476; getindex
   ╎    ╎  1   @Base\dict.jl:289; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   1   @Base\operators.jl:123; isequal
   ╎    ╎    1   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:272; cmp(::SubString{String}, :...
  1╎    ╎    ╎ 1   @Base\iterators.jl:1213; Stateful
   ╎     3   c:\prg\julia\robot6.jl:74; crossdo(::SubString{String}, :...
   ╎    ╎ 3   @Base\dict.jl:476; getindex
  1╎    ╎  1   @Base\dict.jl:279; ht_keyindex(::Dict{String,Ar...
   ╎    ╎  2   @Base\dict.jl:289; ht_keyindex(::Dict{String,Ar...
   ╎    ╎   2   @Base\operators.jl:123; isequal
   ╎    ╎    2   ...\strings\basic.jl:295; ==
   ╎    ╎     1   ...strings\basic.jl:272; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\iterators.jl:1213; Stateful
   ╎    ╎    ╎  1   ...ngs\substring.jl:70; iterate
   ╎    ╎    ╎   1   ...gs\substring.jl:71; iterate
  1╎    ╎    ╎    1   ...trings\basic.jl:194; checkbounds
   ╎    ╎     1   ...strings\basic.jl:274; cmp(::SubString{String}, :...
   ╎    ╎    ╎ 1   @Base\iterators.jl:334; iterate
   ╎    ╎    ╎  1   @Base\iterators.jl:345; _zip_iterate_all
   ╎    ╎    ╎   1   @Base\iterators.jl:351; _zip_iterate_some
   ╎    ╎    ╎    1   ...e\iterators.jl:1263; iterate
   ╎    ╎    ╎     1   ...e\iterators.jl:1256; popfirst!
   ╎    ╎    ╎    ╎ 1   ...s\substring.jl:72; iterate
  1╎    ╎    ╎    ╎  1   @Base\Base.jl:33; getproperty

It seems to me that it shows many calls to split in strings library, also calls to findnext and other string processing.

it probably means most of the time is spent on string processing and the php string code probably has string processing written in c so it would have similar execution time.

I’d look back at how you process strings and see if that could be improved.

For example rather than splitting your string it seems you only use entry 2 and 4 so perhaps just find the first 4 instances of ‘;’ and create substrings of the 2 and 4 components…

I understand the following.
PHP takes 0.758 s
from your post above, Julia currently takes 0.143 s (if all functions are complied / run at least once).

Thus if you get DaemonMode working, you will be at 0.143 s
This can clearly be improved, but it is already a bit faster than PHP. (factor 5)
Admittedly I cannot say whether this comparison is fair/meaningful as I have zero knowledge about PHP (and its compilation/startup time)

you may want to consider these two packages

which may help you identify problematic code pieces

1 Like

You could consider CSV.jl GitHub - JuliaData/CSV.jl: Utility library for working with CSV and other delimited files in the Julia programming language .
This will be MUCH slower for the first time reading the data. For subsequent calls, it should be ‘ok’ though.
But it will allow you to specify the delimiter as ;
s = split(row,";")
should not be necessary anymore, as you can directly read into a DataFrame (or similar).
but this would mean that you also need DataFrames.jl.
hard to say whether this is worth it for your use case, without having the data at hand.

I timed the original code with default and non-default options:

$ hyperfine -i "julia --startup-file=no jl__vs_php.jl"
Benchmark #1: julia --startup-file=no jl_vs_php.jl
  Time (mean ± σ):      2.147 s ±  0.030 s    [User: 2.482 s, System: 0.542 s]

$ hyperfine -i "julia --startup-file=no -O0 --compile=min jl_vs_php.jl"
Benchmark #1: julia --startup-file=no -O0 --compile=min jl_vs_php.jl
  Time (mean ± σ):     442.5 ms ±  41.3 ms    [User: 837.7 ms, System: 499.9 ms]

You might want to use only -O0 or -O1, as it makes parsing of code faster. Note I didn’t have any (of your) files to read, so I got an error (why I used -i), [to the hard coded Windows path, I’m not on Windows.]

I thought there was a SimpleCSV.jl to read small files, I googled and found some others, not sure how many options there are or which is best:

GitHub - tk3369/CSVReader.jl: Simple CSV reader that performs well [EDIT: a bit faster to ‘‘load’’ (I only timed that, not reading actual files) than CSV.jl, on default or non-default settings.]

Another, not registered (and seemingly only for outdated Julia versions): GitHub - cjprybol/uCSV.jl: A Julia package for reading and writing delimited-text; µ in size, ∞ in flexibility

TableReader.jl is supposed to be fast but I got an error using it (precompiling) on Julia 1.3, 1.4, 1.5 and 1.6…

Likely, as I’m sure the code is non-small. But are you sure the latest version is slow 8on first use)? It’s 10-20 faster than CSV readers for other languages, i.e. Python/Pandas (and R), as it’s multi-threaded, but as with all other code, you have to overcome the startup cost, and it may not happen.

Actually CSV.jl is the fastest of all CSV readers I tried to ‘’‘load’‘’ (on default settings), including CSVFiles, Pandas.jl and Fread.jl.

I only timed loading, not actual reading, see here (and benchmark may be outdated):

1 Like