How does Julia compare to shell scripting using bash and its "friends" like bc on a Linux system?

There is a well written section of Julia documentation providing comparisons to some of the other programming languages here:

https://docs.julialang.org/en/v1/manual/noteworthy-differences

What I am missing is comparison with what shell programming using bash and the command line applications coming with a Linux system for arbitrary precision arithmetics like bc is capable of. Which of the in the bash shell available array operations and via bc available arithmetic functionalities are duplicated in Julia and how? What does Julia provide which can’t be achieved with comparable speed using shell scripting and it numerous command line “friends” like for example bc ?

1 Like

Performance is a pretty simple one. With bc, 3^10000000 % 101 takes about 30 seconds, while in Julia

julia> @time big(3)^10000000 % 101
  0.054018 seconds
3 Likes

May you provide the bc code used to obtain this timing?

As I can see you have timed the Julia command without obtaining any kind of output which needs to be calculated (no assignment, no output to stdout).

Does not % has another meaning in Julia as its default meaning (modulo) ?

Shell scripting languages are usually interpreted and therefore for many tasks orders of magnitude slower than compiled languages like Julia. They also lack a proper type system, exceptions etc.

BASH and friends can be useful for programs with less than 20 lines of length. They become a nightmare to read, maintain, test and debug when they become longer.

I use bash scripts to launch Julia and to create Julia system images.

1 Like

The assignment and printing are just printing the literal value 1 (because % is modulo).
To compare including startup, compare

time julia -e "big(3)^10000000 % 101"

real	0m0.627s
user	0m1.264s
sys	0m1.146s

with

echo "3^10000000 % 101" | time bc1
202.55user 0.21system 3:22.94elapsed 99%CPU (0avgtext+0avgdata 24604maxresident)k
0inputs+0outputs (0major+21559minor)pagefaults 0swaps
1 Like

Sorry … but I can’t see any advantage of Julia in the range of numbers which are mostly used in practice, where other cases are extremely rare and need anyway other tools as Julia will fail to cover such cases:

~ $ time python -c "print( 3^100000000000 % 102 )"
91

real	0m0.030s
user	0m0.026s
sys	0m0.004s
~ $ time julia -e "println( big(3)^100000000000 % 102 )"
ERROR: OutOfMemoryError()
Stacktrace:
 [1] pow_ui!(x::BigInt, a::BigInt, b::UInt64)
   @ Base.GMP.MPZ ./gmp.jl:179
 [2] pow_ui
   @ ./gmp.jl:180 [inlined]
 [3] ^
   @ ./gmp.jl:628 [inlined]
 [4] bigint_pow(x::BigInt, y::Int64)
   @ Base.GMP ./gmp.jl:649
 [5] ^
   @ ./gmp.jl:654 [inlined]
 [6] literal_pow(f::typeof(^), x::BigInt, ::Val{100000000000})
   @ Base ./intfuncs.jl:351
 [7] top-level scope
   @ none:1

real	0m0.582s
user	0m0.530s
sys	0m0.174s

Here the timings I consider as more representative as the edge case mentioned:

~ $ time julia -e "println( big(3)^100 % 102 )"
81

real	0m0.242s
user	0m0.206s
sys	0m0.088s
~ $ time echo "3^100 % 102" | bc
81

real	0m0.003s
user	0m0.003s
sys	0m0.000s

3^100 is already a very big number. In practice you won’t go beyond this, but even if see the timings with exponent of 10000 :

~ $ time echo "3^10000 % 102" | bc
69

real	0m0.003s
user	0m0.004s
sys	0m0.000s
~ $ time julia -e "println( big(3)^10000 % 102 )"
69

real	0m0.244s
user	0m0.222s
sys	0m0.073s

big(3)^10000 is:

16313501853426258743032567291811547168121324535825379939348203261918257308143190787480155630847848309673252045223235795433405582999177203852381479145368112501453192355166224391025423628843556686559659645012014177448275529990373274425446425751235537341867387607813619937225616872862016504805593174059909520461668500663118926911571773452255850626968526251879139867085080472539640933730243410152186914328917354576854457274195562218013337745628502470673059426999114202540773175988199842487276183685299388927825296786440252999444785694183675323521704432195785806270123388382931770198990841300861506996108944782065015163410344894945809337689156807686673462563038164792190665340124344133980763205594364754963451564072340502606377790585114123814919001637177034457385019939060232925194471114235892978565322415628344142184842892083466227875760501276009801530703037525839157893875741192497705300469691062454369926795975456340236777734354667139072601574969834312769653557184396147587071260443947944862235744459711204473062937764153770030210332183635531818173456618022745975055313212598514429587545547296534609597194836036546870491771927625214352957503454948403635822345728774885175809500158451837389413798095329711993092101417428406774326126450005467888736546254948658602484494535938888656542746977424368385335496083164921318601934977025095780370104307980276356857350349205866078371806065542393536101673402017980951598946980664330391505845803674248348878071010412918667335823849899623486215050304052577789848512410263834811719236949311423411823585316405085306164936671137456985394285677324771775046050970865520893596151687017153855755197348199659070192954771308347627111052471134476325986362838585959552209645382089055182871854866744633737533217524880118401787595094060855717010144087136495532418544241489437080074716158404895914136451802032446707961058757633345691696743293869623745410870051851590672859347061212573446572045088465460616826082579731686004585218284333452396157730036306379421822435818001505905203918209206969662326706952623512427380240468784114535101496733983401240219840048956733689309620321613793757156727562461651933397540266795963865921590913322060572673349849253303397874242381960775337182730037783698708748781738419747698880321601186310506332869704931303076839444790968339306301273371014087248060946851793697973114432706759288546077622831002526800554849696867710280945946603669593797354642136622231192695027321229511912952940320879763123151760555959496961163141455688278842949587288399100273691880018774147568892650186152065335219113072582417699616901995530249937735219099786758954892534365835235843156112799728164123461219817343904782402517111603206575330527850752564642995318064985900815557979945885931124351303252811255254295797082281946658798705979077492469849644183166585950844953164726896146168297808178398470451561320526180542310840744843107469368959707726836608471817060598771730170755446473440774031371227437651048421606224757527085958515947273151027400662948161111284777828103531499488913672800783167888051177155427285103861736658069404797695900758820465238673970882660162285107599221418743657006872537842677883708807515850397691812433880561772652364847297019508025848964833883225165668986935081274596293983121864046277268590401580209059988500511262470167150495261908136688693861324081559046336288963037090312033522400722360882494928182809075406914319957044927504420797278117837677431446979085756432990753582588102440240611039084516401089948868433353748444104639734074519165067632941419347985624435567342072815910754484123812917487312938280670403228188813003978384081332242484646571417574404852962675165616101527367425654869508712001788393846171780457455963045764943565964887518396481296159902471996735508854292964536796779404377230965723361625182030798297734785854606060323419091646711138678490928840107449923456834763763114226000770316931243666699425694828181155048843161380832067845480569758457751090640996007242018255400627276908188082601795520167054701327802366989747082835481105543878446889896230696091881643547476154998574015907396059478684978574180486798918438643164618541351689258379042326487669479733384712996754251703808037828636599654447727795924596382283226723503386540591321268603222892807562509801015765174359627788357881606366119032951829868274617539946921221330284257027058653162292482686679275266764009881985590648534544939224296689791195355783205968492422636277656735338488299104238060289209390654467316291591219712866052661347026855261289381236881063068219249064767086495184176816629077103667131505064964190910450196502178972477361881300608688593782509793781457170396897496908861893034634895715117114601514654381347139092345833472226493656930996045016355808162984965203661519182202145414866559662218796964329217241498105206552200001

I mean if what you need is exactly covered by bc, then there might not be an advantage to using Julia? there’s no need to use the same tool for everything.

I sometimes use my phone calculator — unfortunately Julia becomes much slower when I have to take the train home to grab my laptop first.

14 Likes

Well, normally you are not doing one calculation, but many in a loop, or you work with vectors and arrays.

For just doing one or two scalar calculations bc is fine, you don’t need Julia for that. We could give a better answer if you would explain your use case.

1 Like

The question is how does Julia compare to shell scripting and the available executable “friends”.
Do I understand it right that Julia startup time is too large so it does not make sense to use it just for some simple calculations even with arbitrary precision exceeding int64 or float128 for single numbers?
Does it make sense to use it for an array of 1080x1920x3 uint8 values where all of the RGB values need to be set to for example the mean value of them?

your question is way too broad and depends on so many details I don’t know how to even begin to answer it.

can you give more context about what concretely you are trying to do?

3 Likes

Julia has some startup time which other things don’t:

$ time julia --startup=no -O0 -e 'println("hello world")'
hello world
real    0m0,149s
$ time echo hello world
hello world
real    0m0,000s
$ time awk 'END {print "hello world"}' < /dev/null
hello world
real    0m0,004s
$ time perl -e 'print "hello world\n"'
hello world
real    0m0,004s

So in many cases the startup latency of julia exceeds the run time of various other linux utilities. For quick scripting, other languages and utilities are often better suited.

1 Like

You’re making many errors.

^ is bitwise exclusive-or in Python, not exponentiation. Try it with ** instead, but be ready to Ctrl-C.

You also increased the exponent by 5 orders of magnitude compared to Oscar_Smith’s example. log2(3^100000000000)=1.585*10^11 bits is 19.8 gigabytes, the software is trying to protect you from crashing the computer with a few integers.

Your timing is including loading the REPL, compiling first calls, and println, those are not representative steps of any number crunching. bash has nice functionality, and if it’s fast enough for you, you shouldn’t bother loading an interactive session in any other language, especially Julia’s relatively hefty runtime. If you need a longer-running number crunching program, bash is not the best tool.

8 Likes

You can use GitHub - dmolina/DaemonMode.jl: Client-Daemon workflow to run faster scripts in Julia if you want to reduce startup time.

1 Like

I am trying to profit from the experience of others which went the way of details in many scenarios down and can tell something generally valid about such comparisons. It is hard to believe that one “language” can be orders of magnitude faster on the same hardware.
What I would like to find out is if shell scripting can cover what other languages provide, so that there is no need for the other languages and proficiency in shell scripting and knowledge about appropriate executable files available on the system would be enough to cover most of the general purpose use cases.

If you go enough into detail … you will loose the chance to arrive at some general valid guidelines … With requesting enough details you can’t compare at all … because at the very detail things are not comparable …

It can provide a small subset, good enough in some use cases as long as the script stays very short. Long shell scripts are not maintainable. And for many tasks like optimization problems, differential equations, machine learning etc shell scripts are no option at all.

2 Likes

This is a universally acknowledged fact. The performance difference between languages like C/C++/Fortran and languages like R/MATLAB/Python in particular is a premise for Julia’s initial development. Many development perks sacrifice performance, which is why people use the latter languages at all. Many languages, including Julia, find their own middle ground and styles.

4 Likes

What is the reason for this? What in detail makes the difference? At the bottom its anyway one CPU-instruction after another … and the file system. So assembly language should be enough for everything in hands of a skilled programmer which orchestrates executable files in a way they provide the result. I suppose that 95% of each programming language is nothing else than duplicating what is already there, but it still requires re-learning these 95% to become able to use it. Orchestrating specialized executable files reading/writing to files (on a RAM-disk) will be then the better way of arriving at any result than usage of some programming language. Shell scripting is orchestrating executable files … in best way possible … so it should be enough to cover all needs, don’t it?

Last release: 2021 … Hmmm … How does it differ from using the REPL and importing the changed source code files?

You’re trying to argue that programming languages are redundant because you can’t see their purposes. Instead of playing out logical fallacies, I would suggest that you learn these languages before making erroneous comparisons and challenges. I can’t possibly speak for all programming languages, but I can broadly respond to a few of your statements.

  1. bash is single-pass interpreted. There is no opportunity for compiler optimizations, which will be present in compiled languages with any interest in performance. It’s even more restricted than CPython, which at least compiles to bytecode before interpretation.
  2. Assembly is not portable, which is why a high level language C is the most accessible programming language. It’s by far the most popular choice for implementing other programming languages.
  3. Yes it all ends up at machine code eventually, but that does not imply it’s just as easy or even feasible to do the same thing in every language. For example, some languages need a runtime to handle things like memory in addition to the code you might find in minimal executables, and the runtime overhead can easily be too much to run on small embedded systems. MicroPython was developed because the CPython implementation was too big for microcontrollers. Julia’s runtime is even bigger in part due to the compiler.
  4. To eliminate the previous factors, let’s limit the conversation to languages compiled to minimal executables. Languages will vary a lot in style and rules, and this affects how people think about programming and the ease of features. Functional programmers enjoy refactorability and reflection benefits from referential transparency. Rust made rules to provide memory safety without the need for a garbage collector. There is no one best language because different people value different tradeoffs.
7 Likes

ninjaaron/administrative-scripting-with-julia: Guide for writing shell scripts in Julia (github.com)

3 Likes