Re:Romeo and Julia, Where Romeo Is Basic Statistics
by jakobnissen on Friday March 15, 2024 @09:49AM
(#39715447)
Isn't it always a good idea to test your implementations against a known correct implementation? Like, if I were testing, say, a SHA implementation, I would also test against the results from an independent implementation. How is this an issue with Julia the language?
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by lolinder on Friday March 15, 2024 @09:59AM
(#39715806)
The way you frame it makes it sound like the author was saying Julia is a less trustworthy language, which isn't what they're saying at all. Here's the quote in context:
> Still, if you are new
to (Julia) programming and statistics then most likely you should calibrate your tools first. Before you run some statistical analysis you may want to try it out on an example from a textbook written by an expert (not me though) and see if you get the same (or at least comparable) result on your own. Although this is a sound approach, I suspect you are more prone to visit some statistical blog or internet forum and go with the examples that are contained there.
One such option is rseek.org, i.e. a search engine for the R programming language.
> ... Once I got both outputs that are similar enough I can be fairly sure I did right. Otherwise I should investigate where the differences come from and possibly make some necessary adjustments.
It doesn't say to compare it against R, it says that if you are new to programming and statistics you should check your work against known-good answers or against a second implementation before rushing ahead, and it gives R as an example of a place to find code that you can use to check your work.
This isn't advice about one language being better, it's the usual advice to solve the same problem in two different ways to make sure you got it right!
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by bachmeier on Friday March 15, 2024 @03:58PM
(#39720023)
The entire point of my comment was that the initial commenter wasn't necessarily saying R is a better language. Somehow you've interpreted my comment as "R is a better language" which is quite far from what it says.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by ngcc_hk on Friday March 15, 2024 @01:40PM
(#39718470)
I suspect what is being said is to compare existing stat textbook but more likely existing stat result of a web site using r. Not to run r but run these and compare the result.
I did the same to r using ibm spss. Not that I trust that more. Just to make sure when newly program you have used the right parameters. If they compare, you finish learning and switch over. A cautious approach when your job is at stake.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by empyrrhicist on Friday March 15, 2024 @09:06AM
(#39715053)
Is anyone aware of a YouTube or tutorial series that goes deep into the graphics stacks for Julia? I can make some plots, but I feel like I'm missing the deeper understanding of what's going on that I have with R base graphics.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by krastanov on Friday March 15, 2024 @12:37PM
(#39717639)
The presentations and workshops about Makie.jl from the last few JuliaCons are pretty good. All recordings from JuliaCon are available at the official Julia youtube channel.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by stared on Friday March 15, 2024 @10:29AM
(#39716161)
I am curious: What is Julia's current niche?
I mean, I tried it a few times a decade ago, but the environment was not mature, and performance improvements were not in the places I needed. Though, I guess, things moved from there.
Python has the richest environment for data science. For statistics, there are some tools in R, such as the stunning ggplot2.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by staplung on Friday March 15, 2024 @11:47AM
(#39717049)
Scientific computing. Of the languages you cited, none (other than Julia) have dynamic dispatch, a feature that turns out to be unexpectedly powerful and allows lots of packages to hang together much more effectively than you would expect.
Also, Rust specifically doesn't have built-in rational numbers, complex numbers, bigints or proper matrixes. There are lots of crates that implement them but that's precisely what prevents a cohesive ecosystem from developing.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by abdullahkhalids on Friday March 15, 2024 @05:54PM
(#39721116)
I don't know anything about this, but the wiki article [1] says that Python, Rust and Julia all have Dynamic dispatch. However, it seems like Python has single dispatch, but Julia has multiple dispatch. Is that what you meant?
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @11:15AM
(#39716681)
> For more complex and performance-intensive programs, I don't see the case for choosing it over a general languages like Rust and C++.
I mean, the fact that it's getting comparable speeds to C++ or Rust, while having full garbage collection and nice built-in concurrency support is a selling point to me. I'm not saying you couldn't write code faster in C++ or Rust, but I'm going to argue that Julia will often be just as fast or faster from "default implement".
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by CyberDildonics on Friday March 15, 2024 @11:47AM
(#39717051)
The garbage collection will cause hiccups and hangs. It isn't faster if you are leaning on garbage collection. Just like any other garbage collected language, you want to avoid the garbage collection.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @12:40PM
(#39717675)
Before I say anything, I think your username is pretty funny. Props for snagging that one.
> It isn't faster if you are leaning on garbage collection. Just like any other garbage collected language, you want to avoid the garbage collection.
I agree in theory but not in practice. Absolutely, if you are good at properly freeing memory, and knowing when to free memory, and how much to free and all that fun stuff, you can definitely get much better performance than a GC, with fewer (or zero) pauses and better throughput.
However, I don't think I agree that that is the average case. A lot of people will simply malloc and free at the beginning and ending of the function, or worse they will do things incorrectly and so the data won't actually free, or it frees before it's completed. A GC does incur some overhead, but they can also be extremely optimized and and have the advantage of doing things basically correctly, or at least safely. If you through multiple threads into the mix, then the problems get much harder.
Julia's doesn't do this, but GC in languages like Go also basically don't cause hiccups or hangs, at least not long ones. The pause times are sub-millisecond [1], and it's pretty impressive. Even Java, the language that initially gave GC's a bad name, has the Shenandoah GC in some builds of OpenJDK which also gets sub-millisecond pauses [2].
Personally, I tend to believe that an application that stops working is generally "slower" than one that keeps working. A lot of the time savings you get from avoiding a GC will be eliminated if your program crashes and restarts.
(That said, I will acknowledge that Rust probably makes this much better; I haven't done anything "real" with Rust so I cannot comment on it.)
What I was trying to say was that Julia, at least in benchmarks, does get speeds getting close to something like C++, even with GC enabled, and it will certainly run circles around something like Python. If you want something that gets around at least 80+% of the speed of C++, while also giving all the prettiness and easiness of Python, I think Julia is a very good choice, and I would happily choose it over something like Go.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by CyberDildonics on Friday March 15, 2024 @01:08PM
(#39718039)
A lot of people will simply malloc and free at the beginning and ending of the function, or worse they will do things incorrectly and so the data won't actually free, or it frees before it's completed
I don't think programming mistakes in other languages make a point when talking about garbage collection performance.
but they can also be extremely optimized
Every language I've ever seen with garbage collection has gone through decades of "now the garbage collection is better" or "just wait until the next version, garbage collection will be better". I've seen it in java, D, julia and every scripting language. It's always a thorn people have to work around when talking about performance interactivity. Julia is right in the middle of this common problem and that is fine for what it is because it isn't a typical systems language and avoiding the gc is not difficult, but to pretend that it is the same as C++ is just not true.
A lot of the time savings you get from avoiding a GC will be eliminated if your program crashes and restarts.
This is besides the point of performance and no longer talking about reality, it's just FUD from a "what if" future.
Julia, at least in benchmarks, does get speeds getting close to something like C++, even with GC enabled
Right, but you get it by avoiding allocation and avoiding the garbage collector the same way avoiding allocation in C++ is important, but in julia it won't be woven in to the performance, it will cause big pauses.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by samatman on Friday March 15, 2024 @03:04PM
(#39719488)
Slow is slow and fast is fast. For some reason you consider it cheating to not ref-count everything in C++ to get speed, but writing idiomatic Julia code which does minimal allocation is somehow out of bounds. You'd decided what you want to believe and are working backward from there.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @01:24PM
(#39718269)
> Every language I've ever seen with garbage collection has gone through decades of "now the garbage collection is better" or "just wait until the next version, garbage collection will be better".
Ok but the Go example I linked is already in production, right now, you can use it. This isn't a "it will get better in two releases" situation, Go's GC as of today has pause times that are sub-millisecond. The Java Shenandoah example I linked is still mostly in beta, but it's also something you can use right now, though admittedly it'll probably be awhile before it's in a mainline release.
> This is besides the point of performance and no longer talking about reality, it's just FUD from a "what if" future.
It's not "just FUD", there are dozens of reported security issues that have happened because of bad manual memory management problems. Off the top of my head, Heartbleed was a famous case.
This isn't me badmouthing anyone; manual memory management is hard to get right, even for very smart people.
> Right, but you get it by avoiding allocation and avoiding the garbage collector the same way avoiding allocation in C++ is important, but in julia it won't be woven in to the performance, it will cause big pauses.
Fair enough, I did look at the code for the official benchmarks (https://github.com/JuliaLang/Microbenchmarks/blob/master/per...) and outside of the integer parsing code it does indeed seem to avoid dynamic allocations so I will concede that the benchmarks might be a bit more skewed compared to real-world code.
I still get a hunch that if you compared it allocation-heavy Julia to malloc+free-heavy C++ the differences wouldn't really be that far off, but that's just a hunch and I don't have data to back that up; might be a fun test to write though, so maybe I'll try that this weekend.
-----
Sort of tangential, but I also do think that there's value in having decent concurrency constructs built into the language. With C++, if you stick to built-ins you are basically stuck with mutexes and despite what people like to pretend, getting correct code with mutexes is really really hard to get right, and very easy to screw up in a non-obvious way. If you allow yourself to use libraries, then you have stuff like ZeroMQ and OpenMP and stuff, so it's really not that dire realistically. However, I think there's value in having nice, easy to use concurrency constructs in the language other than mutexes, and I do wonder if as a result of that it encourages people to utilize multiple threads more frequently, because they don't have to worry about weird deadlock situations as much.
Again, I believe Rust actually does address this because of the single-owner-enforced-at-compile-time stuff, but I haven't used it enough to really draw a conclusion on it.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by CyberDildonics on Friday March 15, 2024 @04:00PM
(#39720056)
Ok but the Go example
This was a thread about julia and garbage collection, you keep talking about unrelated things and trying to go off in all sorts of other directions.
manual memory management is hard to get right, even for very smart people.
This is very different in modern C++, I basically never have memory problems since the actual allocation is minimal and inside value types.
if you compared it allocation-heavy Julia to malloc+free-heavy C++ the differences wouldn't really be that far off
The point is that if you care about performance you don't do either of these. If you try this you will see that they are both much slower than they need to be, but julia will pause and hiccup because of the gc.
With C++, if you stick to built-ins you are basically stuck with mutexes
This is a bizarre and unrelated tangent, but it's so wrong I figured I would say something. Not only does the standard library have great primitives, but there are great libraries out there for lock free queues, lock free hash maps and openmp for fork join parallelism. I don't think anyone has concurrency nailed down but julia is not any better.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @04:17PM
(#39720248)
> This was a thread about julia and garbage collection, you keep talking about unrelated things and trying to go off in all sorts of other directions.
Yes, but I was referring specifically to your statement "Just like any other garbage collected language, you want to avoid the garbage collection." I took issue with that statement. I think you know that and you're pretending to not.
> This is very different in modern C++, I basically never have memory problems since the actual allocation is minimal and inside value types.
Fair, maybe my C++ is out of date.
> The point is that if you care about performance you don't do either of these. If you try this you will see that they are both much slower than they need to be, but julia will pause and hiccup because of the gc.
You keep asserting different, slightly contrary things, and are restating things that I've already conceded to. The statement "if you really care about performance" is doing a lot of work; most realistic code isn't hyper optimized to remove all allocations and the like. Most code is written by mediocre engineers. Julia gives very good speeds, comparable to C++, in those situations.
If you're doing high frequency trading or something then sure, maybe you're writing this hyper optimized code. In my experience that's not typical, and the initial point I argued that you took issue with for reasons I have to admit I still don't understand is this: Julia can be used for general purpose stuff in place of C++ and Rust, and you'll get decent performance while also having full garbage collection.
> This is a bizarre and unrelated tangent, but it's so wrong I figured I would say something.
In the thing you're responding to I said it was a tangent so acting like I'm changing the subject unprompted is weird. I also mentioned OpenMP and mentioned that this wasn't a problem realistically, so I don't see why you felt the need to restate it.
Now I again will restate that I am aware that C++ has libraries to do this, you don't need to pretend that I didn't say that. You can get nice distributed computing support with ZeroMQ or Nanomsg and probably a dozen other libraries.
Honestly though, this entire topic is frustrating to me because you're getting to the point of outright dishonesty.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by CyberDildonics on Friday March 15, 2024 @04:32PM
(#39720408)
I don't even know what you are trying to say. All I said was that if you lean on garbage collection, julia is not going to be the same as C++ because it will pause and hiccup. Everything else you hallucinated into half a dozen splintered arguments.
Julia has parallel for loops out of the box
Every major C++ compiler has openmp built in. Julia is great but I think you should study up on C++ if you want to compare them.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by samatman on Friday March 15, 2024 @03:01PM
(#39719437)
> the JIT compile times made it unfeasible
Worth trying again unless that was in the last 18 months. Precompilation has gotten dramatically faster, like 50x improvement in load times faster. So has startup time in general, `time julia -e "return 5"` gave 161 milliseconds of user time on my computer. I don't actually use Julia for simple script munging, simply because I'm used to Python in that role and it works fine, but it's suitable for it.
Calculator-like use? Julia, all the way. Of course I keep the REPL open at all times. Gotta use tools the way they're intended, y'know?
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by the__alchemist on Friday March 15, 2024 @03:10PM
(#39719553)
I'll give it a shot! I've been tracking a steady stream of published improvements this area over the years (decade?)
I think the most striking moment I had was when I realized through experiment that rust, which has a notoriously slow compiler, was faster to compile and run a small plotting program than Julia. That was ~5 years ago though!
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by samatman on Friday March 15, 2024 @07:09PM
(#39721630)
Entirely different language when it comes to compile times, they were tremendously successful in the time-to-first-plot project. 1.6 was the release in 2021 that made the biggest difference, but with steady improvement since.
The big push now is to add everything needed so that making object/dylib code in Julia of comparable size to the usual systems languages is possible. The team has a track record of finishing what they start, I'm optimistic that they'll get that right as well.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by sampo on Friday March 15, 2024 @11:35AM
(#39716910)
> What is Julia's current niche?
Python, but for engineers and scientists. Syntax is friendlier for doing mathematics, barrier to entry to first calculation script is lower
a = [1 2 3]
b = [4 5 6]
a + b
vs
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
a + b
Also you can learn Julia step by step, and improve your code to run faster. Whereas in Python, the eventual road to fast code is to write the library in C and call it from Python.
Python is for software people. Matlab, Julia and R are for people who only write code because they want answers.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by sampo on Friday March 15, 2024 @02:24PM
(#39719034)
> Python is for software people. Matlab, Julia and R are for people who only write code because they want answers.
Or, Julia can be for both.
Julia lets you start from scientific calculations scripts and grow your code to a larger software package. Same as Python grew popular 20 years ago because it let you grow your small sysadmin scripts to larger software.
Matlab and R are too limited in their "real programming language" constructs, and it gets painful when your codebase grows larger. Julia has all "real programming language" constructs a software engineer would need.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by jakobnissen on Saturday March 16, 2024 @06:44AM
(#39724739)
I use it for high-performance scientific code. Code that needs to run fast, be written fast, and frequently extended and modified, with a mix of high and low level computing.
This could be achieved by a mix of Python and Rust, but it's just too annoying to write scripts in two languages, where one is compiled and the other has terrible package management. Much easier to write it in Julia and have it be fast out of the box
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @11:12AM
(#39716648)
My dad recently had me help him port some Matlab code to a web service. He eventually ported it over to Octave so I could run it, since I don't have any kind of license for Matlab. I couldn't find any good web server implementations for Octave, so I was looking for free "matlab-like" languages that might, and I found Julia. The code wasn't stats-heavy, but it was heavily number-crunchy, making heavy use of matrices and tensors and stuff that admittedly still kind of goes over my head.
I've not done a lot with "numeric" programming, but I was able to pick up Julia really quickly, and I was able to do a more-or-less straight port of my dad's code to Julia. What I was extremely impressed with was how much faster it went out of the box; for some of the more crunchy bits, running on the same hardware, the Julia code ran quite literally 150x faster, and this was without any Julia-specific optimizations other than adding types to the function arguments.
Since then I've learned a lot more about Julia, to a point where it has sort of become my go-to language for starting new projects (assuming I don't need to use a specific JVM library or something). It's basically guaranteed to give me fast code out of the box, it has most of the concurrency constructs that I actually care about, it has a better-than-average macro system (at least compared to something like C++), and personally I just think that the language looks pretty once you get into some more of the details. I wish it were a more popular language, because the only thing that has held me back from using it more has been the lack of library support. Most of the libraries are fine, but for example I had a lot of trouble getting the Bcrypt library working, which is something I wouldn't really have a problem with on a JVM language or C++ or something.
Of course, this is (hopefully) a temporary problem, as the language slowly grows in popularity the library support should just get better.
ETA:
I haven't done proper benchmarks on this so this is purely speculation, but that said I think that the biggest boost comes from the fact that Julia properly optimizes loops. My dad is a smart dude, but not being a software engineer in 2024, didn't really know that using loop constructs in most higher-level language is considered a code smell. I don't now about Octave, but I know in Python it's generally considered way better to try and avoid vanilla "loops" and try and convert looping things into some kind of vector operation.
I think the JIT part of Julia is smart enough to optimize loops out of the box, and so my straight port of my dad's code just "magically" got faster, and I was extremely impressed, but I suspect that if my dad had utilized a lot of the vector operations of Octave and/or Matlab, the results wouldn't be nearly as impressive. I suspect Julia would still have performed better (if nothing else because I was able to add type information), but I suspect it wouldn't be the 100+X speed increase that I was getting.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by affinepplan on Friday March 15, 2024 @01:50PM
(#39718608)
> and this was without any Julia-specific optimizations other than adding types to the function arguments.
I know this wasn't the point of your post, but just noting that adding types to function arguments "usually" shouldn't impact performance at all :)
when it does, that might mean there is some type-instability being papered over (i.e. there is a better fix lurking around the corner)
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @02:06PM
(#39718799)
In one case adding type information into the function args, for a function with a loop being run like 20 million times, it made a pretty substantial difference; it brought processing down from roughly 2 minutes to roughly 10 seconds.
I didn't do a control test to figure out exactly why, but I think it was having some issue with a parsed CSV being read as a matrix. I think explicitly putting that requirement into the function signature allowed for a lot of low-level optimizations to be used that it couldn't use before.
I'm not 100% sure though; basically when I was getting some performance bottlenecks I did some preliminary searching and some of the results said "try adding types to your function signatures", and I really couldn't think of a good reason not to add them for most of the variables, and so I did and it worked.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by samatman on Friday March 15, 2024 @02:54PM
(#39719365)
What grants speed to Julia code is type assertions, at least in the case where the assertions lead to type stability. The compiler balances speed (of compilation) and accuracy, when inferring types and deciding what methods to specialize. If and when it can't figure that out, adding a type assert give it more ability to assume the assertion is accurate.
Concrete types in a function signature also work as assertions, so it's one way to force the compiler's hand this way. In many cases it's better to assert the arguments, rather than the parameters, to keep the method itself generic. The main reason to add types to a method is to allow multiple dispatch to pick that method of the function for values of the specified type.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by tombert on Friday March 15, 2024 @03:02PM
(#39719455)
That makes sense; basically giving a hint so that the compiler can figure out what kind of special optimizations are possible. I would assume that it can avoid extra reflection calls as well as a result?
The slow function I added the types to didn't really make any sense to be really generic. For nearly all the arguments (of which there was like 20), there was only one type that made any sense for each. I don't think keeping it more generic would have bought me much, and adding types worked as an assertion that made things much faster.
But yes, once I started adding types to thing, I did start utilizing multiple dispatch, since I've always been a bit fan of Clojure-style multimethods and this got me something more or less comparable to it.
Re:Romeo and Julia, Where Romeo Is Basic Statistics
by ChrisRackauckas on Thursday March 21, 2024 @04:01AM
(#39775857)
> Concrete types in a function signature also work as assertions, so it's one way to force the compiler's hand this way. In many cases it's better to assert the arguments, rather than the parameters, to keep the method itself generic. The main reason to add types to a method is to allow multiple dispatch to pick that method of the function for values of the specified type.
No they do not, this is not how it works. Functions auto-specialize on the types they see and do a multiple dispatch behind the scenes on these specializations. Type parameters in a function signature thus only define what specializations are allowed. See https://book.sciml.ai/notes/02-Optimizing_Serial_Code/ for details. As such, you don't need to add any types to a function signature to get performance.
> So I guess it’s gonna be about a programming language named Julia and its usage for basic statistics.
This writing is weird, you are the author right?
http://poignant.guide/book/chapter-2.html
https://learnyouahaskell.com/introduction
this is just a normal sanity check and is not a strike against Julia (or R)
> Still, if you are new to (Julia) programming and statistics then most likely you should calibrate your tools first. Before you run some statistical analysis you may want to try it out on an example from a textbook written by an expert (not me though) and see if you get the same (or at least comparable) result on your own. Although this is a sound approach, I suspect you are more prone to visit some statistical blog or internet forum and go with the examples that are contained there. One such option is rseek.org, i.e. a search engine for the R programming language.
> ... Once I got both outputs that are similar enough I can be fairly sure I did right. Otherwise I should investigate where the differences come from and possibly make some necessary adjustments.
It doesn't say to compare it against R, it says that if you are new to programming and statistics you should check your work against known-good answers or against a second implementation before rushing ahead, and it gives R as an example of a place to find code that you can use to check your work.
This isn't advice about one language being better, it's the usual advice to solve the same problem in two different ways to make sure you got it right!
I did the same to r using ibm spss. Not that I trust that more. Just to make sure when newly program you have used the right parameters. If they compare, you finish learning and switch over. A cautious approach when your job is at stake.
[1] https://gadflyjl.org/stable/dev/pipeline
[2] https://giovineitalia.github.io/Compose.jl
Since the LLM breakout on Huggingface, I am back in Python world.
I mean, I tried it a few times a decade ago, but the environment was not mature, and performance improvements were not in the places I needed. Though, I guess, things moved from there.
Python has the richest environment for data science. For statistics, there are some tools in R, such as the stunning ggplot2.
For numerics-heavy arrays, we have PyTorch.
For custom low-level numerics, Rust rocks.
Also, Rust specifically doesn't have built-in rational numbers, complex numbers, bigints or proper matrixes. There are lots of crates that implement them but that's precisely what prevents a cohesive ecosystem from developing.
[1] https://en.wikipedia.org/wiki/Dynamic_dispatch
I tried to use it for quick scripts and calculator-like-use, but the JIT compile times made it unfeasible. (Julia's math syntax is the best I've seen)
For more complex and performance-intensive programs, I don't see the case for choosing it over a general languages like Rust and C++.
I mean, the fact that it's getting comparable speeds to C++ or Rust, while having full garbage collection and nice built-in concurrency support is a selling point to me. I'm not saying you couldn't write code faster in C++ or Rust, but I'm going to argue that Julia will often be just as fast or faster from "default implement".
> It isn't faster if you are leaning on garbage collection. Just like any other garbage collected language, you want to avoid the garbage collection.
I agree in theory but not in practice. Absolutely, if you are good at properly freeing memory, and knowing when to free memory, and how much to free and all that fun stuff, you can definitely get much better performance than a GC, with fewer (or zero) pauses and better throughput.
However, I don't think I agree that that is the average case. A lot of people will simply malloc and free at the beginning and ending of the function, or worse they will do things incorrectly and so the data won't actually free, or it frees before it's completed. A GC does incur some overhead, but they can also be extremely optimized and and have the advantage of doing things basically correctly, or at least safely. If you through multiple threads into the mix, then the problems get much harder.
Julia's doesn't do this, but GC in languages like Go also basically don't cause hiccups or hangs, at least not long ones. The pause times are sub-millisecond [1], and it's pretty impressive. Even Java, the language that initially gave GC's a bad name, has the Shenandoah GC in some builds of OpenJDK which also gets sub-millisecond pauses [2].
Personally, I tend to believe that an application that stops working is generally "slower" than one that keeps working. A lot of the time savings you get from avoiding a GC will be eliminated if your program crashes and restarts.
(That said, I will acknowledge that Rust probably makes this much better; I haven't done anything "real" with Rust so I cannot comment on it.)
What I was trying to say was that Julia, at least in benchmarks, does get speeds getting close to something like C++, even with GC enabled, and it will certainly run circles around something like Python. If you want something that gets around at least 80+% of the speed of C++, while also giving all the prettiness and easiness of Python, I think Julia is a very good choice, and I would happily choose it over something like Go.
[1] https://groups.google.com/g/golang-dev/c/Ab1sFeoZg_8
[2] https://wiki.openjdk.org/display/shenandoah/Main#Main-Perfor...
I don't think programming mistakes in other languages make a point when talking about garbage collection performance.
but they can also be extremely optimized
Every language I've ever seen with garbage collection has gone through decades of "now the garbage collection is better" or "just wait until the next version, garbage collection will be better". I've seen it in java, D, julia and every scripting language. It's always a thorn people have to work around when talking about performance interactivity. Julia is right in the middle of this common problem and that is fine for what it is because it isn't a typical systems language and avoiding the gc is not difficult, but to pretend that it is the same as C++ is just not true.
A lot of the time savings you get from avoiding a GC will be eliminated if your program crashes and restarts.
This is besides the point of performance and no longer talking about reality, it's just FUD from a "what if" future.
Julia, at least in benchmarks, does get speeds getting close to something like C++, even with GC enabled
Right, but you get it by avoiding allocation and avoiding the garbage collector the same way avoiding allocation in C++ is important, but in julia it won't be woven in to the performance, it will cause big pauses.
Ok but the Go example I linked is already in production, right now, you can use it. This isn't a "it will get better in two releases" situation, Go's GC as of today has pause times that are sub-millisecond. The Java Shenandoah example I linked is still mostly in beta, but it's also something you can use right now, though admittedly it'll probably be awhile before it's in a mainline release.
> This is besides the point of performance and no longer talking about reality, it's just FUD from a "what if" future.
It's not "just FUD", there are dozens of reported security issues that have happened because of bad manual memory management problems. Off the top of my head, Heartbleed was a famous case.
This isn't me badmouthing anyone; manual memory management is hard to get right, even for very smart people.
> Right, but you get it by avoiding allocation and avoiding the garbage collector the same way avoiding allocation in C++ is important, but in julia it won't be woven in to the performance, it will cause big pauses.
Fair enough, I did look at the code for the official benchmarks (https://github.com/JuliaLang/Microbenchmarks/blob/master/per...) and outside of the integer parsing code it does indeed seem to avoid dynamic allocations so I will concede that the benchmarks might be a bit more skewed compared to real-world code.
I still get a hunch that if you compared it allocation-heavy Julia to malloc+free-heavy C++ the differences wouldn't really be that far off, but that's just a hunch and I don't have data to back that up; might be a fun test to write though, so maybe I'll try that this weekend.
-----
Sort of tangential, but I also do think that there's value in having decent concurrency constructs built into the language. With C++, if you stick to built-ins you are basically stuck with mutexes and despite what people like to pretend, getting correct code with mutexes is really really hard to get right, and very easy to screw up in a non-obvious way. If you allow yourself to use libraries, then you have stuff like ZeroMQ and OpenMP and stuff, so it's really not that dire realistically. However, I think there's value in having nice, easy to use concurrency constructs in the language other than mutexes, and I do wonder if as a result of that it encourages people to utilize multiple threads more frequently, because they don't have to worry about weird deadlock situations as much.
Again, I believe Rust actually does address this because of the single-owner-enforced-at-compile-time stuff, but I haven't used it enough to really draw a conclusion on it.
This was a thread about julia and garbage collection, you keep talking about unrelated things and trying to go off in all sorts of other directions.
manual memory management is hard to get right, even for very smart people.
This is very different in modern C++, I basically never have memory problems since the actual allocation is minimal and inside value types.
if you compared it allocation-heavy Julia to malloc+free-heavy C++ the differences wouldn't really be that far off
The point is that if you care about performance you don't do either of these. If you try this you will see that they are both much slower than they need to be, but julia will pause and hiccup because of the gc.
With C++, if you stick to built-ins you are basically stuck with mutexes
This is a bizarre and unrelated tangent, but it's so wrong I figured I would say something. Not only does the standard library have great primitives, but there are great libraries out there for lock free queues, lock free hash maps and openmp for fork join parallelism. I don't think anyone has concurrency nailed down but julia is not any better.
Yes, but I was referring specifically to your statement "Just like any other garbage collected language, you want to avoid the garbage collection." I took issue with that statement. I think you know that and you're pretending to not.
> This is very different in modern C++, I basically never have memory problems since the actual allocation is minimal and inside value types.
Fair, maybe my C++ is out of date.
> The point is that if you care about performance you don't do either of these. If you try this you will see that they are both much slower than they need to be, but julia will pause and hiccup because of the gc.
You keep asserting different, slightly contrary things, and are restating things that I've already conceded to. The statement "if you really care about performance" is doing a lot of work; most realistic code isn't hyper optimized to remove all allocations and the like. Most code is written by mediocre engineers. Julia gives very good speeds, comparable to C++, in those situations.
If you're doing high frequency trading or something then sure, maybe you're writing this hyper optimized code. In my experience that's not typical, and the initial point I argued that you took issue with for reasons I have to admit I still don't understand is this: Julia can be used for general purpose stuff in place of C++ and Rust, and you'll get decent performance while also having full garbage collection.
> This is a bizarre and unrelated tangent, but it's so wrong I figured I would say something.
In the thing you're responding to I said it was a tangent so acting like I'm changing the subject unprompted is weird. I also mentioned OpenMP and mentioned that this wasn't a problem realistically, so I don't see why you felt the need to restate it.
Are these the concurrency primitives you're talking about? https://en.cppreference.com/w/cpp/thread
Sure, those are fine, but I dispute that they're as generally-useful as CSP style message passing. Moreover, Julia has parallel for loops out of the box (https://julialang.org/blog/2019/07/multithreading/), in addition to having built in support for not only parallel computing, but also distributed computing across multiple nodes (https://docs.julialang.org/en/v1/manual/distributed-computin...).
Now I again will restate that I am aware that C++ has libraries to do this, you don't need to pretend that I didn't say that. You can get nice distributed computing support with ZeroMQ or Nanomsg and probably a dozen other libraries.
Honestly though, this entire topic is frustrating to me because you're getting to the point of outright dishonesty.
Julia has parallel for loops out of the box
Every major C++ compiler has openmp built in. Julia is great but I think you should study up on C++ if you want to compare them.
Worth trying again unless that was in the last 18 months. Precompilation has gotten dramatically faster, like 50x improvement in load times faster. So has startup time in general, `time julia -e "return 5"` gave 161 milliseconds of user time on my computer. I don't actually use Julia for simple script munging, simply because I'm used to Python in that role and it works fine, but it's suitable for it.
Calculator-like use? Julia, all the way. Of course I keep the REPL open at all times. Gotta use tools the way they're intended, y'know?
I think the most striking moment I had was when I realized through experiment that rust, which has a notoriously slow compiler, was faster to compile and run a small plotting program than Julia. That was ~5 years ago though!
The big push now is to add everything needed so that making object/dylib code in Julia of comparable size to the usual systems languages is possible. The team has a track record of finishing what they start, I'm optimistic that they'll get that right as well.
Python, but for engineers and scientists. Syntax is friendlier for doing mathematics, barrier to entry to first calculation script is lower
vs Also you can learn Julia step by step, and improve your code to run faster. Whereas in Python, the eventual road to fast code is to write the library in C and call it from Python.Python is for software people. Matlab, Julia and R are for people who only write code because they want answers.
Or, Julia can be for both.
Julia lets you start from scientific calculations scripts and grow your code to a larger software package. Same as Python grew popular 20 years ago because it let you grow your small sysadmin scripts to larger software.
Matlab and R are too limited in their "real programming language" constructs, and it gets painful when your codebase grows larger. Julia has all "real programming language" constructs a software engineer would need.
This could be achieved by a mix of Python and Rust, but it's just too annoying to write scripts in two languages, where one is compiled and the other has terrible package management. Much easier to write it in Julia and have it be fast out of the box
I've not done a lot with "numeric" programming, but I was able to pick up Julia really quickly, and I was able to do a more-or-less straight port of my dad's code to Julia. What I was extremely impressed with was how much faster it went out of the box; for some of the more crunchy bits, running on the same hardware, the Julia code ran quite literally 150x faster, and this was without any Julia-specific optimizations other than adding types to the function arguments.
Since then I've learned a lot more about Julia, to a point where it has sort of become my go-to language for starting new projects (assuming I don't need to use a specific JVM library or something). It's basically guaranteed to give me fast code out of the box, it has most of the concurrency constructs that I actually care about, it has a better-than-average macro system (at least compared to something like C++), and personally I just think that the language looks pretty once you get into some more of the details. I wish it were a more popular language, because the only thing that has held me back from using it more has been the lack of library support. Most of the libraries are fine, but for example I had a lot of trouble getting the Bcrypt library working, which is something I wouldn't really have a problem with on a JVM language or C++ or something.
Of course, this is (hopefully) a temporary problem, as the language slowly grows in popularity the library support should just get better.
ETA:
I haven't done proper benchmarks on this so this is purely speculation, but that said I think that the biggest boost comes from the fact that Julia properly optimizes loops. My dad is a smart dude, but not being a software engineer in 2024, didn't really know that using loop constructs in most higher-level language is considered a code smell. I don't now about Octave, but I know in Python it's generally considered way better to try and avoid vanilla "loops" and try and convert looping things into some kind of vector operation.
I think the JIT part of Julia is smart enough to optimize loops out of the box, and so my straight port of my dad's code just "magically" got faster, and I was extremely impressed, but I suspect that if my dad had utilized a lot of the vector operations of Octave and/or Matlab, the results wouldn't be nearly as impressive. I suspect Julia would still have performed better (if nothing else because I was able to add type information), but I suspect it wouldn't be the 100+X speed increase that I was getting.
I know this wasn't the point of your post, but just noting that adding types to function arguments "usually" shouldn't impact performance at all :) when it does, that might mean there is some type-instability being papered over (i.e. there is a better fix lurking around the corner)
I didn't do a control test to figure out exactly why, but I think it was having some issue with a parsed CSV being read as a matrix. I think explicitly putting that requirement into the function signature allowed for a lot of low-level optimizations to be used that it couldn't use before.
I'm not 100% sure though; basically when I was getting some performance bottlenecks I did some preliminary searching and some of the results said "try adding types to your function signatures", and I really couldn't think of a good reason not to add them for most of the variables, and so I did and it worked.
Concrete types in a function signature also work as assertions, so it's one way to force the compiler's hand this way. In many cases it's better to assert the arguments, rather than the parameters, to keep the method itself generic. The main reason to add types to a method is to allow multiple dispatch to pick that method of the function for values of the specified type.
The slow function I added the types to didn't really make any sense to be really generic. For nearly all the arguments (of which there was like 20), there was only one type that made any sense for each. I don't think keeping it more generic would have bought me much, and adding types worked as an assertion that made things much faster.
But yes, once I started adding types to thing, I did start utilizing multiple dispatch, since I've always been a bit fan of Clojure-style multimethods and this got me something more or less comparable to it.
No they do not, this is not how it works. Functions auto-specialize on the types they see and do a multiple dispatch behind the scenes on these specializations. Type parameters in a function signature thus only define what specializations are allowed. See https://book.sciml.ai/notes/02-Optimizing_Serial_Code/ for details. As such, you don't need to add any types to a function signature to get performance.