[HN Gopher] Julia 1.6 Highlights
___________________________________________________________________
 
Julia 1.6 Highlights
 
Author : 3JPLW
Score  : 308 points
Date   : 2021-03-25 14:45 UTC (8 hours ago)
 
web link (julialang.org)
w3m dump (julialang.org)
 
| cbkeller wrote:
| See also Lyndon's blog post [1] about what all has changed since
| 1.0, for anyone who's been away for a while.
| 
| [1] https://www.oxinabox.net/2021/02/13/Julia-1.6-what-has-
| chang...
 
| f6v wrote:
| Is there a per-project way to manage dependencies yet? I find
| global package installation to be the biggest weakness of all the
| R projects out there. Anaconda can help, but it's not widely used
| for R projects. And Docker... well, don't get me started.
 
  | eigenspace wrote:
  | Yes, absolutely. Julia has very strong per-project dependency
  | tracking and reproducibility.
 
  | adgjlsfhk1 wrote:
  | Yeah. Julia's had that since (at least) 1.0. Environments are
  | built-in, and you specify project dependencies in a
  | Projects.toml file https://pkgdocs.julialang.org/v1/toml-
  | files/.
 
    | staticfloat wrote:
    | Small nitpick; its Project.toml (or JuliaProject.toml, to
    | avoid name clashes) not Projects.toml
 
    | UncleOxidant wrote:
    | Or you can activate a local project in a directory, add
    | packages and the Project.toml gets created for you.
 
    | oxinabox wrote:
    | Since 0.7 (which was 1.0 with deprecations) In julia 0.6 and
    | before it was exactly as bad as described. (though there were
    | things like Playground.jl to kind of work around it)
 
  | krastanov wrote:
  | I might be misunderstanding your question, but this post is
  | about Julia, not R. Julia has a pretty great per-project
  | dependency management.
 
    | 00117 wrote:
    | Julia is a competitor of R, hence the comparison.
 
  | psychometry wrote:
  | renv is how R projects do per-package dependency management.
  | Before renv there was packrat. This has been a solved problem
  | for years now...
 
    | f6v wrote:
    | Doesn't mean it's adopted though.
 
| odipar wrote:
| I like Julia (mostly because of multiple dispatch). The only
| thing that's lacking is an industry strength Garbage Collector,
| something that can be found in the JVM.
| 
| I know that you shouldn't produce garbage, but I happen to like
| immutable data structures and those work better with optimised
| GCs.
 
  | superdimwit wrote:
  | A low-latency GC would also be great. But again, the JVM only
  | has that due to many millions of dollars spent over decades.
 
  | eigenspace wrote:
  | Julia's garbage collector is quite good.
  | 
  | > I know that you shouldn't produce garbage, but I happen to
  | like immutable data structures and those work better with
  | optimised GCs.
  | 
  | If you use immutable data-structures in julia, you're rather
  | unlikely to end up with any heap allocations at all. Unlike
  | Java, Julia is very capable of stack allocating user defined
  | types.
 
  | newswasboring wrote:
  | I didn't even know julia GC had issues. Care to elaborate?
 
    | adgjlsfhk1 wrote:
    | The biggest struggle Julia's GC has is that in multi-threaded
    | workloads, it sometimes isn't aggressive enough to reclaim
    | memory leading to OOM.
 
      | StefanKarpinski wrote:
      | This is very legit issue that the compiler team has their
      | eye on and plans to work on.
 
        | adgjlsfhk1 wrote:
        | fyi, I'm oscardssmith on most other channels.
 
        | StefanKarpinski wrote:
        | Hi, Oscar! Nice user name :P
 
    | StefanKarpinski wrote:
    | It doesn't, it just doesn't have a $100B GC like Java does.
    | Rather than spending that kind of money trying to compensate
    | for a language design that generates massive amounts of
    | garbage (ie Java), Julia takes the approach of making it
    | easier to avoid generating garbage in the first place, eg by
    | using immutable structures that can be stack allocated and
    | having nice APIs for modifying pre-allocated data structures
    | in place.
 
      | odipar wrote:
      | I don't think you can allocate immutable data structures on
      | the stack.
      | 
      | I've never seen a 10 million entry immutable set on the
      | stack but I could be wrong.
 
        | StefanKarpinski wrote:
        | Obviously a 10-million-element array doesn't get stack
        | allocated. But if individual objects of some type are
        | immutable, then they can be stack allocated, or maybe not
        | allocated at all (kept in registers).
        | 
        | Edit: reading your other post, it seems like you may mean
        | persistent data structures, a la Clojure, rather than
        | immutable structures, which are quite different. The
        | former would indeed always be heap-allocated (it's
        | necessary since they are quite pointer-heavy). Immutable
        | structures, on the other hand are detached from any
        | particular location in memory.
        | 
        | Moreover, if the elements in an array are mutable, eg
        | Java objects, then each one needs to be individually heap
        | allocated with a vtable pointer and the array has to be
        | an array of pointers to those individually allocated
        | objects. For pointer-sized objects (say an object that
        | has a single pointer-sized field), that takes 3x memory
        | to store x objects, so that's already brutal, but worse
        | is that since the objects are all individually allocated,
        | the GC needs to look at every single one, and freeing the
        | space is a fragmentation nightmare. If the objects are
        | immutable (and the type is final; btw _all_ concrete
        | types are final in Julia), then you can store them inline
        | with no overhead and GC can deal with them a single big
        | block.
        | 
        | Btw, I had to vouch for you to undead your posts in order
        | to reply. Looks like you got downvoted a bunch.
 
      | leephillips wrote:
      | Ouch.
 
        | StefanKarpinski wrote:
        | I mean I'm not trying to hate on Java -- pointer-heavy
        | programming was all the rage when it was designed, and GC
        | was a hot research topic, so there was good reason to be
        | optimistic about that approach. But it turns out that
        | it's very hard to make up for generating tons of garbage
        | and pointer-heavy programming hasn't aged well given the
        | way hardware has evolved (pointers are large and
        | indirection is expensive).
 
        | leephillips wrote:
        | Hating on Java seems perfectly reasonable to me.
 
        | odipar wrote:
        | so are you _for_ GC or _against_ GC?
        | 
        | In other posts you actually argue that GCs help you
        | reduce complexity because manual memory management is too
        | much of a hassle.
        | 
        | May be immutable is not the correct term - persistent
        | data structures is what I like support for: that is my
        | use-case.
        | 
        | I think you can have efficient persistent data structures
        | without a GC, but that requires fast reference counting
        | and in turn, that requires a lot of work to be
        | competitive with the JVM.
        | 
        | I also understand that my use-case is not Julia's focus.
        | That's perfectly fine.
 
        | StefanKarpinski wrote:
        | I love GC -- it solves a ton of nasty problems in a
        | programming language design with a single feature that
        | users mostly don't have to worry about. Just because you
        | have a GC, however, doesn't mean that it's a good idea to
        | generate as much garbage as you can -- garbage collection
        | isn't free. That's where Java IMO went wrong. Java's
        | design -- objects are and subtypeable (by default) and
        | mutable with reference semantics -- generates an absolute
        | epic amount of garbage. It seems like the hope was that
        | improvements in GC technology would make this a non-issue
        | in the future, but we're in the future and it hasn't
        | turned out that way: even with vast amounts of money that
        | have been spent on JVM GCs, garbage is still often an
        | issue in Java. And this has given GC _in general_ a bad
        | name IMO quite unfairly. It just happens that Java
        | simultaneously popularized GC _and_ gave it a bad name by
        | having a design that made it virtually impossible for the
        | GC to keep up with the amount of garbage that was
        | generated.
        | 
        | It is entirely possible to design a garbage collected
        | language that doesn't generate so goddamned much garbage
        | -- and this works much, much better because a relatively
        | simple GC can easily keep up. Julia and Go are good
        | examples of this. Julia uses immutable types extensively
        | and by default, while Go uses value semantics, which has
        | a similar effect on garbage (but has other issues). With
        | a language design that doesn't spew so much garbage, if
        | you only care about throughput, a relatively simple
        | generational mark-and-sweep collector is totally fine.
        | This is what Julia has. If you also want to minimize GC
        | pause latency, then you need to get fancier like Go (I
        | think they have a concurrent collector that can be paused
        | when it's time slice is up and resumed later).
        | 
        | Persistent data structures are a whole different question
        | that I haven't really spent much time thinking about.
        | Clojure seems to be the state of the art there but I have
        | no idea if that's because of the JVM or despite it.
 
        | pron wrote:
        | > garbage is still often an issue in Java.
        | 
        | Not anymore. That future is here. Java is getting
        | "flattenable" types not because of GC, but because of
        | iteration.
 
        | StefanKarpinski wrote:
        | Has a version of Java with value types been released?
 
        | pron wrote:
        | No, but there's now a JEP, which normally means that
        | release is imminent (I'm not involved with that project,
        | so I have no inside information):
        | https://openjdk.java.net/jeps/401
        | 
        | As part of this change, existing built-in primitive types
        | (like int or double) will retroactively become instances
        | of these more general objects.
 
        | odipar wrote:
        | Thanks for the reply!
        | 
        | Unfortunately, persistent data structures tend to produce
        | (short-lived) garbage which the JVM is very good at
        | collecting!
        | 
        | So yes, Clojure benefits immensely from the JVM.
        | 
        | It is also an interesting research topic whether
        | (optimised) reference counting would be a better
        | approach.
        | 
        | Regarding objects, there is also a "middle ground" to
        | consider:
        | 
        | Split big (immutable) arrays in smaller ones, connect
        | them with some pointers in between, and you are still
        | cache friendly.
        | 
        | Also, you can do a lot on the application level to reduce
        | garbage, and most Java programmers don't care for that
        | exactly _because_ of JVM.
 
        | ChrisRackauckas wrote:
        | That's a major oversimplification. GC is good for ease of
        | use and safety of a high level language. GC is never as
        | performant as not requiring heap allocations at all.
        | Julia has a GC, but also provides a lot of tools to avoid
        | needing the GC in high performance computations. This
        | combination gives ease of use and performance.
        | 
        | Java sacrifices some performance for having this "one
        | paradigm" of all objects, and then heavily invested in
        | the GC, but in many cases like writing a BLAS it still
        | just will not give performance exactly matching a highly
        | tuned code, where as in Julia for example you can write
        | really fast BLAS codes like Octavian.jl.
        | 
        | Julia is multi-paradigm in a way that is purposely
        | designed for how these features compose. I think it's
        | important to appreciate that design choice, in both its
        | pros and cons.
 
        | StefanKarpinski wrote:
        | I don't know that the object model is why writing a BLAS
        | in Java doesn't make sense. After all they special case
        | `float` and `double` as primitives, which bifurcates the
        | whole type system and is its own whole issue, but means
        | that you can store them efficiently inline. I'm actually
        | not sure what stops someone from writing a BLAS in Java
        | except that it would be hard and there's no point.
 
        | celrod wrote:
        | To tie Octavian.jl into this memory allocation
        | discussion:
        | 
        | Octavian uses stack-allocated temporaries when "packing"
        | left matrix ("A" in "A*B"). These temporaries can have
        | tens of thousands of elements, so that's a non-trivial
        | stack allocation (the memory is mutable to boot). No heap
        | allocations or GC activity needed (just a GC.@preserve to
        | mark its lifetime). If I understand correctly, this isn't
        | something that'd be possible in Java?
        | 
        | To be fair, you can also just use preallocated global
        | memory for your temporaries, since the maximum amount of
        | memory needed is known ahead of time.
 
        | odipar wrote:
        | I like your response, and yes, it was a major
        | oversimplification and I'm sorry for that.
        | 
        | Indeed, it is always about design choices and trade-offs.
        | I can see why BLAS code is important and why Julia is an
        | optimal choice for computation heavy problems.
 
        | pron wrote:
        | You're mixing two things here: memory management and
        | memory layout. This "pointer-heavy programming" is,
        | indeed, a bad fit for modern hardware in terms of
        | processing speed due to cache misses, which is why even
        | Java is now getting user-defined primitive types (aka
        | inline types, aka value types), but in terms of memory
        | management, in recent versions OpenJDK is pretty
        | spectacular, not only in throughput but also latency (ZGC
        | in JDK 16 has sub millisecond maximum pause time for any
        | size of heap and up to a very respectable allocation
        | rate: https://malloc.se/blog/zgc-jdk16 and both
        | throughput and max allocation rate are expected to grow
        | drastically in the coming year with ZGC becoming
        | generational). As far as performance is concerned, GC can
        | now be considered a solved problem (albeit one that
        | requires a complex implementation); the only real price
        | you pay is in footprint overhead.
 
        | StefanKarpinski wrote:
        | I'm not -- memory layout and memory management are
        | (fairly obviously, I would think) intimately related. In
        | particular, pointer-heavy memory layouts put way more
        | stress on the garbage collector. Java's choice of making
        | objects mutable, subtypeable and have reference
        | semantics, basically forces them to be individually heap-
        | allocated and accessed via pointers. On the other hand,
        | if you design your language so that you can avoid heap
        | allocating lots of individual objects, then you can get
        | away with a much simpler garbage collector. Java only
        | needs spectacular GC technology because the language is
        | designed in such a way that it generates a spectacular
        | amount of garbage.
 
        | pron wrote:
        | I would say no. To have stellar performance, you'll need
        | compaction, you'll need parallelism (of GC threads), and
        | you'll need concurrency between the GC threads and
        | mutator threads; and for good throughput/footprint
        | tradeoff you'll need generational collection. True, you
        | might not need to contend with allocation rates that are
        | that high, but getting, say, concurrent compaction (as in
        | ZGC) and/or partial collections (as in G1), requires a
        | sophisticated GC. E.g. Go isn't as pointer-heavy as (pre-
        | Valhalla) Java, and its GC is simple and offers very good
        | latency, but it doesn't compact and it throttles, leading
        | to lower throughput (I mean total program sluggishness)
        | than you'd see in Java, even with a much higher
        | allocation rate. The thing is that even with a low
        | allocation rate, you'd get some challenging heaps, only
        | later, say, every 10 seconds instead of every 5.
        | 
        | It's true that a simpler GC might get you acceptable
        | performance for your requirements if your allocation rate
        | is relatively low, but you still won't get OpenJDK
        | performance. So I'd say that if you design your language
        | to require fewer objects, then you can get by with a
        | simple GC _if_ your performance requirements aren 't too
        | demanding.
        | 
        | All that dereferencing puts a higher load on data
        | structure traversal (which is why Java is getting
        | "flattenable" types) than on the GC. The main reason for
        | Java's particular GC challenges isn't its pointer-heavy
        | (pre-Valhalla) design but the mere fact that it is the
        | GCed platform that sees the heaviest workloads and most
        | challenging requirements by far. Java's GC needs to work
        | hard mostly for the simple reason that Java is asked to
        | do _a lot_ (and the better some automated mechanism
        | works, the more people push it).
 
        | bbatha wrote:
        | Go has only concurrency of the features you talk about
        | but is often competitive with Java in benchmarks. In my
        | experience I'll take administration of go processes any
        | day of the week over Java -- I've lost count of the
        | number of hours lost to debugging gc stalls, runaway
        | heaps and other garbage collector related issues never
        | once had those problems in go.
        | 
        | Go even reverted a generational collector because it had
        | no performance benefits since most generational objects
        | would be stack allocated anyway -- Julia's JIT and way
        | more advanced llvm backend should do even better than go
        | in keeping objects stack local and inline.
 
        | pron wrote:
        | It's competitive in pretty forgiving benchmarks. And LLVM
        | is way more advanced than Go's compiler, but not
        | OpenJDK's. I'm not saying you have to prefer Java to Go,
        | but its throughput _is_ better. As to the stack-
        | allocation claim, young generations might be hundreds of
        | MBs; that might correspond to the stacks of 100K
        | goroutines on some server workloads, but not of a few
        | threads.
        | 
        | So I'm not saying you must prefer Go to Java, or that
        | Go's performance isn't adequate for many reasonable
        | workloads, only that 1. a flatter object landscape might
        | still not match Java's memory management performance
        | without sophisticated GCs, and 2. I wouldn't extrapolate
        | from Go to Julia, as they are languages targeting very
        | different workloads. E.g. Julia might well prefer higher
        | throughput over lower latency, and Go's GC's throughput
        | is not great.
 
| siproprio wrote:
| On 1.6, I tried "] add Plots" and julia got stuck.
 
  | StefanKarpinski wrote:
  | Please file an issue describing the situation:
  | https://github.com/JuliaLang/julia/issues/new
 
    | siproprio wrote:
    | After the issue, I nuked the .julia folder, and now it is
    | taking too long to clone the "JuliaRegistries/General.git"
    | repo.
    | 
    | By the download speed, it might take a few hours before I can
    | plot something.
    | 
    | It also seems that just doing "git clone
    | JuliaRegistries/General.git" is much faster than doing "] add
    | Plots"
 
      | siproprio wrote:
      | > (@v1.6) pkg> add Plots Installing known registries into
      | `~\\.julia` Cloning registry from
      | "https://github.com/JuliaRegistries/General.git" Fetching:
      | [==> ] 3.4 %
      | 
      | I gave up because it's just too slow (more than 15 min to
      | get to 3%).
      | 
      | Maybe plotting is indeed faster, but I don't think I'll
      | actually get to that point.
 
        | 3JPLW wrote:
        | Is your home folder on a network drive?
 
        | siproprio wrote:
        | Nope.
 
        | the_duke wrote:
        | Did you try a manual git clone to rule out any network or
        | FS issues?
 
        | siproprio wrote:
        | A manual git clone is very slow for the Julia registry,
        | but it's still an order of magnitude faster...
 
      | dagw wrote:
      | Is this on Windows? I've experienced the same for the past
      | few releases in Windows. For some reason that clone step is
      | ridiculously slow.
 
        | siproprio wrote:
        | Yes.
 
        | oxinabox wrote:
        | Window registry issues have been a thing.
        | 
        | I have heard it is to do with how windows antivirus
        | works. Since the registry is like 10,000 seperate files.
        | It chokes on them.
        | 
        | I have heard there is an upcoming feature to allow the
        | package manager to work with the registry being kept
        | inside a tarball, which is specifically being added to
        | deal with this
 
| 3JPLW wrote:
| The feature I'm most excited about is the parallel -- and
| automatic -- precompilation. Combined with the iterative latency
| improvements, Julia 1.6 has far fewer coffee breaks.
 
  | shmeano wrote:
  | or sword fights https://xkcd.com/303/
 
    | yesenadam wrote:
    | Ohh, is that what the programmers were doing all through
    | _Halt and Catch Fire_? Waiting for compilation? I couldn 't
    | understand how they got away with acting like naughty 5 year
    | olds, throwing things at each other constantly.
 
| systems wrote:
| I know its minor, but I still hope they will fix scoping
| 
| not that my suggestion is good, but what they have now is bad
| 
| https://github.com/JuliaLang/julia/issues/37187
 
  | StefanKarpinski wrote:
  | Has been fixed since 1.5.
 
    | systems wrote:
    | no it has not, they now have different rules for repl, which
    | is part of scope awkwardness
 
    | patagurbon wrote:
    | Should that issue be closed then?
 
      | systems wrote:
      | Its a suggestion to fix the awkwardness, one that will
      | never get approved
      | 
      | "Put your code into functions, people!" .. is the reason
      | why most people dont notice the weird scoping rules
      | 
      | You will only hit the weirdness face first, if you write
      | scripts with global variables, which is usually what
      | beginners do
      | 
      | Most advanced users, and library writers, probably hardly
      | notice it
 
| MisterBiggs wrote:
| I've been running the 1.6 release candidates, and the compilation
| speed improvements have been massive. There have been plenty of
| instances in the past where I've tried to 'quickly' show off some
| Julia code, and I end up waiting ~45 seconds for a plot to show
| or a minute for a Pluto notebook to run, and that's not to
| mention waiting for my imports to finish. It's still slower than
| Matlab for the first run, but it's at least in the same ballpark
| now.
 
  | Sukera wrote:
  | What kind of speed do you see now?
 
    | leephillips wrote:
    | I've also been running the release candidates, and I get
    | something like 6 seconds to first plot on my 2013 laptop,
    | including the time for `using Plots` and the time to actually
    | draw the first plot. A huge improvement; kudos to the
    | developers.
 
    | MisterBiggs wrote:
    | No idea if this is really a fair comparison but just to get a
    | brief idea of current speeds:                  julia> @time
    | let               using Plots               plot([sin, cos])
    | end             11.267558 seconds (17.98 M allocations: 1.114
    | GiB, 4.83% gc time)
    | 
    | Versus Matlab which probably takes about 15 seconds just to
    | open the editor but plotting is very fast.
    | >> tic        fplot( @(x) [sin(x) cos(x)])        toc
    | Elapsed time is 0.374394 seconds.
    | 
    | Julia is just about as fast as Matlab after the first run for
    | plotting.
 
      | siproprio wrote:
      | > Matlab which probably takes about 15 seconds just to open
      | the editor
      | 
      | Try this:
      | 
      | matlab -nosplash -nodesktop -r "tic; fplot( @(x) [sin(x)
      | cos(x)]); toc"
 
        | eigenspace wrote:
        | I believe that's still not going to capture the startup
        | time of Matlab itself, right?
 
        | siproprio wrote:
        | It's faster than opening the editor, though.
 
      | dan-robertson wrote:
      | I wonder how much Julia could be helped with some
      | uneval/image-saving magic. So when you run the repl you
      | instead get a pre-built binary with plot already loaded and
      | several common specialisations already compiled.
 
        | staticfloat wrote:
        | We call these "system images" and you can generate them
        | with [PackageCompiler](https://github.com/JuliaLang/Packa
        | geCompiler.jl). Unfortunately, it's still a little
        | cumbersome to create them, but this is something that
        | we're improving from release to release. One possible
        | future is where an environment can be "baked", such that
        | when you start Julia pointing to that environment (via
        | `--project`) it loads all the packages more or less
        | instantaneously.
        | 
        | The downside is that generating system images can be
        | quite slow, so we're still working on ways to generate
        | them incrementally. In any case, if you're inspired to
        | work on this kind of stuff, it's definitely something the
        | entire community is interested in!
 
  | peatmoss wrote:
  | In terms of "don't make me think about why Julia is fast but
  | feels slow for casual use" this release is going to be a game
  | changer.
  | 
  | I just did a "using Plots" in 1.6.0, and it was fast enough to
  | not care about the delta between Plots and, say, R loading
  | ggplot.
  | 
  | Huge kudos to the Julia team.
 
| xiphias2 wrote:
| Cool, I was thinking of downloading the RC, the demo was so
| impressive.
| 
| Will there be an M1 Mac version for 1.7?
 
  | thetwentyone wrote:
  | I think so - Julia master branch (1.7 precursor) works on M1,
  | but not all the dependencies that some packages require have
  | been built for M1. Though, I understand that the wonderful
  | packaging system and the folks who work on it are working on
  | it.
  | 
  | > `git clone https://github.com/JuliaLang/julia` and `make`
  | should be enough at this point.
  | 
  | https://github.com/JuliaLang/julia/issues/36617#issuecomment...
 
    | xiphias2 wrote:
    | Cool, I'll start with 1.6, but it looks interesting of course
    | :)
 
    | staticfloat wrote:
    | Yeah, we've managed to get Julia itself running pretty well
    | on the M1, there are still a few outstanding issues such as
    | backtraces not being as high-quality as on other platforms.
    | You can see the overall tracking issue [0] for a more
    | granular status on the platform support.
    | 
    | For the package ecosystem as a whole, we will be slowly
    | increasing the number of third-party packages that are built
    | for aarch64-darwin, but this is a major undertaking, so I
    | don't expect it to be truly "finished" for 3-6 months. This
    | is due to both technical issues (packages may not build
    | cleanly on aarch64-darwin and may need some patching/updating
    | especially since some of our compilers like gfortran are
    | prerelease testing builds, building for aarch64-darwin means
    | that the packages must be marked as compatible with Julia
    | 1.6+ only--due to a limitation in Julia 1.5-, etc...) as well
    | as practical (Our packaging team is primarily volunteers and
    | they only have so much bandwidth to help fix compilation
    | issues).
    | 
    | [0] https://github.com/JuliaLang/julia/issues/36617
 
      | xiphias2 wrote:
      | That's great, releasing something that isn't yet ready
      | doesn't make sense. But when it works, it's important
      | enough to warrant a release :)
 
| JulianMorrison wrote:
| BTW, broken link on the documentation page, "The documentation is
| also available in PDF format: julia-1.6.0.pdf." No it isn't.
 
  | 3JPLW wrote:
  | Thanks for the report:
  | 
  | https://github.com/JuliaLang/julia/issues/40190
  | 
  | Edit: it's now building:
  | 
  | https://github.com/JuliaLang/docs.julialang.org/runs/2196972...
 
    | JulianMorrison wrote:
    | Much appreciated.
 
| snicker7 wrote:
| On the package ecosystem side, 1.6 is required for JET.jl [0].
| Despite being a dynamic language, the Julia compiler does a lot
| of static analysis (or "abstract interpretation" in Julia lingo).
| JET.jl exposes some of this to the user, opening a path for
| additional static analysis tools (or maybe even custom
| compilers).
| 
| [0]: https://github.com/aviatesk/JET.jl
 
  | celrod wrote:
  | > or maybe even custom compilers
  | 
  | Like for autodiff or GPUs.
 
  | akdor1154 wrote:
  | Good gracious, thanks for this. If JET goes anywhere, then
  | that+other goodies in 1.6 mean I will likely switch back from
  | Python+mypy.
 
| wiz21c wrote:
| Whatever improves loading times is more than welcome. It's not
| really acceptable to wait because you import some libraries. In
| understand Julia makes lots of things under the hood and that
| there's a price to pay for that but being a python user, it's a
| bit inconvenient.
| 
| But I'll sure give it a try because Julia hits a sweet spot
| between expressiveness and speed (at least for the kind of stuff
| I do : matrix, algorithms, graphs computations).
 
| beeforpork wrote:
| Julia is such a wonderful language. There are many design
| decisions that I like, but most importantly to me, its ingenious
| idea of combining multiple dispatch with JIT compilation still
| leaves me in awe. It is such an elegant solution to achieving
| efficient multiple dispatch.
| 
| Thanks to everyone who is working on this language!
 
  | skohan wrote:
  | What does it mean exactly? Or what is novel here?
 
    | ddragon wrote:
    | This video is good explaining the idea behind multiple
    | dispatch in Julia if you have time:
    | 
    | https://www.youtube.com/watch?v=kc9HwsxE1OY
 
    | JulianMorrison wrote:
    | It's like C++ template specialisation, but it happens when
    | the compiler realises you need a particular version. Which
    | may be at runtime, if you changed something.
 
      | dan-robertson wrote:
      | Except the language can choose from suitable templates (eg
      | instead of a generic matrix multiply template for floats,
      | it can use a library like LAPACK) and does so in a
      | systematic way.
      | 
      | It also has a feature (I can't recall the name) which is a
      | bit like fexprs (let's say macros who's inputs are the
      | types of the arguments of a function) that can generate
      | customised code (eg an FFT depending on the input size) on
      | the fly.
 
  | pjmlp wrote:
  | I advise you to check Common Lisp CLOS and Dylan.
 
    | dan-robertson wrote:
    | Common lisp's typesystem is just not really as useful for
    | this sort of thing. In particular it doesn't have parameter
    | used types so you can't make eg a matrix of complex numbers.
    | This breaks (1) a lot of the opportunity for optimisation by
    | inlining (because you can't assume that all the
    | multiplications in your matrix{float} multiplication are
    | regular float multiplications) or generic code (because you
    | can't have a generic matrix type and need a special float-
    | matrix); and (2) opportunities for saving memory with generic
    | data structures because the types must be associated to the
    | smallest units and not the container (eg every object in a
    | float matrix must be tagged with the fact that it is a float
    | because in theory you could put a complex number in there and
    | then you'd need to know to do a different multiplication
    | operation).
    | 
    | I guess you could try to hack together some kind of
    | templating feature to make new type-specific classes on the
    | fly, but this won't work well with subtyping. Your template
    | goes system could probably have (matrix float) as a subclass
    | of matrix, but not of (matrix real) or (matrix number). I
    | think you'd lose too much in Common Lisp's hodge-podge type
    | system.
    | 
    | A big innovation of Julia was figuring out how to make
    | generic functions and multiple dispatch work in a good way
    | with the kind of generic data structures you need for good
    | performance. And this was not a trivial problem at all.
    | Julia's system let's you write generic numeric matrix code
    | while still having float matrix multiplication done by
    | LAPACK, which seems desirable.
    | 
    | The other thing is that Julia is a language where generic
    | functions are a low-level thing all over the standard library
    | whereas Common Lisp has a mix of a few generic functions (er,
    | documentation is one; there are more in cltl2), a few "pre-
    | clos" generic functions like mathematical functions, sequence
    | functions and to some extent some array functions, and a
    | whole lot of non-generic functions.
 
    | iib wrote:
    | Wikipedia has a nice table [1] on the Multiple Dispatch page,
    | that describes one studies' findings about the use of
    | multiple dispatch in languages supporting it, in practice.
    | 
    | Although CLOS and others do support it, Julia seems to take
    | the cake by most metrics, highlighting that it is a core
    | paradigm of the language, more so than in the others.
 
    | eigenspace wrote:
    | What the OP is talking about is julia's method-based JIT
    | strategy coupling very well to multiple dispatch.
    | 
    | JIT is not new, multiple dispatch is not new, and multiple
    | dispatch + JIT also isn't new, but nmo existing langauges
    | combined them in a way that allows for the fantastic,
    | efficient devirtualization of generic methods that julia is
    | so good at.
    | 
    | This is why things like addition and multiplication are not
    | generic functions in Common Lisp, it's too slow in CL because
    | the CLOS is not able to efficiently devirtualize the
    | dispatch. In julia, everything is a generic function, and we
    | use this fact to great effect.
    | 
    | CLOS and Dylan laid a ton of important groundwork for these
    | developments, but they're also not the same.
 
      | fiddlerwoaroof wrote:
      | It's not true that CLOS generic dispatch is slow: Robert
      | Strandh and other have done a bunch of work showing that
      | it's possible to implement it efficiently without giving up
      | the dynamic redefinition features that make CLOS such a
      | nice system. There's at least one video game project
      | (Kandria) that's been funding an implementation of these
      | ideas so that generic functions can be used in a soft real-
      | time system like a video game.
      | 
      | The really nice thing about CLOS, though, is that the meta-
      | object protocol lets you choose an implementation of OOP
      | that makes sense for your use-case.
 
        | eigenspace wrote:
        | Yes, I don't doubt at all that it's _possible_ to make
        | CLOS dispatch fast. What I 'm saying is that because
        | historically people using CLOS had to pay a (often
        | negligible) runtime cost for dispatch, it limited the
        | number of places developers were willing to allow generic
        | dispatch.
        | 
        | Julia makes the runtime cost of (type stable) dispatch
        | zero, and hence does not even give julia programmers an
        | *option* to write non-generic functions (though it can be
        | hacked in like with FunctionWrappers.jl). I'm not
        | familiar with Strandh's work, but has it made the
        | overhead of generic functions low, or has it completely
        | eliminated it?
        | 
        | Another thing I'll mention is that Julia's type system is
        | parametric, and we allow values (not just types) in our
        | type parameters which is immensely useful for writing
        | generic high performance code. You can specialize methods
        | on matrices of complex integers separately from rank 5
        | arrays of rational Int8s for instance. This is not a
        | capability that CLOS or Dylan has as far as I'm aware,
        | though the common refrain is that you can do it with
        | macros, but that neglects that it's rather hard to get
        | right, and will have limited use because such macro
        | implementations of type parameters won't be ubiquitious.
        | 
        | ________________________________
        | 
        | To be clear though, I'm not hating on Common Lisp or
        | CLOS. The Common Lisp ecosystem is awesome and can do all
        | sorts of really cool things that I wish we had in julia.
        | I'm mostly just pushing back on the notion that Julia
        | doesn't do anything new or interesting.
 
    | ddragon wrote:
    | Languages with multiple dispatch aren't rare, but a language
    | having it as the core language paradigm, combined with a
    | compiler capable of completely resolving the method calls
    | during compile time, and therefore able to remove all runtime
    | costs of the dispatch, and a community that fully embraced
    | the idea of creating composable ecosystems is something
    | unique to Julia. I don't think anyone has scaled multiple
    | dispatch to the level of Julia's ecosystem before.
 
      | pjmlp wrote:
      | Depends, most use SBCL instead of paying for Allegro or
      | LispWorks, so the perception is skewed.
 
| pjmlp wrote:
| Love the improvements, all those little details that improve the
| overall usability.
 
| fermienrico wrote:
| Are the performance claims of Julia greatly exaggerated?
| 
| Julia loses almost consistently to Go, Crystal, Nim, Rust,
| Kotlin, Python (PyPy, Numpy):
| https://github.com/kostya/benchmarks
| 
| Is this because of bad typing or they didn't use Julia properly
| in idiomatic manner?
 
  | adgjlsfhk1 wrote:
  | They are measuring compile time, not runtime speed.
 
    | stabbles wrote:
    | They are measuring compile time and runtime speed, not _just_
    | runtime speed like for statically compiled langauges
 
      | stjohnswarts wrote:
      | Is that truly accurate though ? I could see them comparing
      | say load time of data files plus execution time but
      | combining compile times in there doesn't make much sense.
      | You always have to pay for it in julia but not with a
      | statically compiled file.
 
        | dklend122 wrote:
        | You only pay for it on the first run.
 
      | dunefox wrote:
      | Where does it say that?
 
        | [deleted]
 
        | ZeroCool2u wrote:
        | I'm not a huge Julia user, but typically if they don't
        | specifically mention they're segmenting runtime from
        | compilation time with Julia, that's a bit of a red flag,
        | because unlike Rust, Go, or C++ the compilation step
        | isn't separate in Julia. To the user it just looks like
        | it's running, when in reality it's compiling, then
        | running, without really letting you know in between.
 
        | cygx wrote:
        | In the matrix multiplication example, the measurement is
        | done via a simple                   t = time()
        | results = calc(n)         elapsed = time() - t
        | 
        | So startup time at least isn't included.
        | 
        | One might argue that this is still biased against Julia
        | due to its compilation strategy, but fixing that would
        | mean you'd have to figure out what the appropriate way to
        | get 'equivalent' timings for any of the other languages
        | would be as well - something far more involved than just
        | slapping a timer around a block of code in all cases...
        | 
        |  _edit:_ As pointed out below, the Julia code should
        | indeed already have been  'warmed up' due to a preceding
        | sanity check. My apologies for 'lying'...
 
        | 3JPLW wrote:
        | The problem is a minor placement issue for the `@simd`
        | macro: https://github.com/kostya/benchmarks/pull/317
 
        | komuher wrote:
        | If u cant even read code dont lie xD                   n
        | = length(ARGS) > 0 ? parse(Int, ARGS[1]) : 100
        | left = calc(101)  # <------- THIS IS COLD START JITTING
        | CALL         right = -18.67         if abs(left - right)
        | > 0.1             println(stderr, "$(left) != $(right)")
        | exit(1)         end              notify("Julia (no
        | BLAS)\t$(getpid())")         t = time()         results =
        | calc(n)         elapsed = time() - t
        | notify("stop")
 
        | stabbles wrote:
        | not sure why this was downvoted to oblivion, as it seems
        | to be correct
 
        | detaro wrote:
        | presumably because of the tone.
 
        | stabbles wrote:
        | Ah, I have to take that back, since benchmarks run in the
        | order of seconds and they use sockets to start and stop
        | the timer, which likely means compilation time is not
        | included.
 
  | StefanKarpinski wrote:
  | This appears to be a set of benchmarks of how fast a brainfuck
  | interpreter implemented in different programming languages is
  | on a small set of brainfuck programs? What a bizarre thing to
  | care about benchmarks for. Are you planning on using Julia by
  | writing brainfuck code and then running it through an
  | interpreter written in Julia?
 
    | fermienrico wrote:
    | Seems like you're the founder of Julia. Why such a knee jerk
    | reaction? Did you read the benchmark page? The table of
    | content is right at the top.
    | 
    | Optics of this type of reaction is seen everywhere in the
    | Julia community. My advice is to embrace negativity around
    | the language, try to understand if it is fabrication or
    | legitimate, and address the shortcomings.
    | 
    | Julia is a beautiful language and hope some of the warts of
    | the language gets fixed.
 
      | StefanKarpinski wrote:
      | When I wrote that I was under the impression that the
      | brainfuck interpreter implementations were the _only_
      | benchmarks in the repo. There are, however (I now realize),
      | also benchmarks for base64 decoding, JSON parsing, and
      | writing your own matmul (rather than calling a BLAS matmul,
      | which is not generally recommended), so this is more
      | reasonable than I thought but still a somewhat odd
      | collection of tasks to benchmark. Of course,
      | microbenchmarks are hard -- they are all fairly arbitrary
      | and random.
      | 
      | In a delightful twist, it seems that there is a Julia
      | implementation of a Brainfuck JIT that is much faster than
      | the fastest interpreter that is benchmarked here, so even
      | by this somewhat esoteric benchmark, Julia ends up being
      | absurdly fast.
      | 
      | https://news.ycombinator.com/item?id=26585042
 
      | CyberDildonics wrote:
      | Don't be ridiculous. If someone puts emphasis on nonsense,
      | dismissing it is reasonable.
 
      | [deleted]
 
  | [deleted]
 
  | stabbles wrote:
  | I think it's more interesting to see what people do with the
  | language instead of focusing on microbenchmarks. There's for
  | instance this great package
  | https://github.com/JuliaSIMD/LoopVectorization.jl which exports
  | a simple macro `@avx` which you can stick to loops to vectorize
  | them in ways better than the compiler (=LLVM). It's quite
  | remarkable you can implement this in the language as a package
  | as opposed to having LLVM improve or the julia compiler team
  | figure this out.
  | 
  | See the docs which kinda read like blog posts:
  | https://juliasimd.github.io/LoopVectorization.jl/stable/
  | 
  | And then replacing the matmul.jl with the following:
  | @avx for i = 1:m, j = 1:p             z = 0.0             for k
  | = 1:n                 z += a[i, k] * b[k, j]             end
  | out[i, j] = z         end
  | 
  | I get a 4x speedup from 2.72s to 0.63s. And with @avxt
  | (threaded) using 8 threads it goes town to 0.082s on my amd
  | ryzen cpu. (So this is not dispatching to MKL/OpenBLAS/etc).
  | Doing the same in native Python takes 403.781s on this system
  | -- haven't tried the others.
 
  | SatvikBeri wrote:
  | I've rewritten two major pipelines from numpy-heavy, fairly
  | optimized Python to Julia and gotten a 30x performance
  | improvement in one, and 10x in the other. It's pretty fast!
 
  | otde wrote:
  | I think this particular Julia code is pretty misleading, and
  | I'm (probably) one of the most qualified people in this
  | particular neck of the woods. I wrote a transpiler for Julia
  | that converts a Brainfuck program to a native Julia function at
  | parse time, which you can then call like you would any other
  | julia function.
  | 
  | Here's code I ran, with results:                 julia> using
  | GalaxyBrain, BenchmarkTools            julia> bench = bf"""
  | >++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++
  | [>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++
  | ++++++++[>++++++++++[>++++++++++[>++++++++++[>+
  | +++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++."""
  | julia> @benchmark $(bench)(; output=devnull, memory_size=100)
  | BenchmarkTools.Trial:          memory estimate:  352 bytes
  | allocs estimate:  3         --------------         minimum
  | time:     96.706 ms (0.00% GC)         median time:      97.633
  | ms (0.00% GC)         mean time:        98.347 ms (0.00% GC)
  | maximum time:     102.814 ms (0.00% GC)         --------------
  | samples:          51         evals/sample:     1
  | julia> mandel = bf"(not printing for brevity's sake)"
  | julia> @benchmark $(mandel)(; output=devnull, memory_size=500)
  | BenchmarkTools.Trial:          memory estimate:  784 bytes
  | allocs estimate:  3         --------------           minimum
  | time:     1.006 s (0.00% GC)         median time:      1.009 s
  | (0.00% GC)         mean time:        1.011 s (0.00% GC)
  | maximum time:     1.022 s (0.00% GC)           --------------
  | samples:          5  evals/sample:     1
  | 
  | Note that, conservatively, GalaxyBrain is about 8 times faster
  | than C++ on "bench.b" and 13 times faster than C on "mandel.b,"
  | with each being the fastest language for the respective
  | benchmarks. In addition, it allocates almost no memory relative
  | to the other programs, which measure memory usage in _MiB_.
  | 
  | You could argue that I might see similar speedup for other
  | languages on my machine, assuming I have a spectacularly fast
  | setup, but this person ran their benchmarks on a tenth
  | generation Intel CPU, whereas mine's an eighth generation Intel
  | CPU:                 julia> versioninfo()         Julia Version
  | 1.5.1         Commit 697e782ab8 (2020-08-25 20:08 UTC)
  | Platform Info:  OS: Linux (x86_64-pc-linux-gnu)         CPU:
  | Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz           WORD_SIZE:
  | 64         LIBM: libopenlibm  LLVM: libLLVM-9.0.1 (ORCJIT,
  | skylake)
  | 
  | This package is 70 lines of Julia code. You can check it out
  | for yourself here: https://github.com/OTDE/GalaxyBrain.jl
  | 
  | I talk about this package in-depth here:
  | https://medium.com/@otde/six-months-with-julia-parse-time-tr...
 
    | Sukera wrote:
    | @btime reports the minimum execution time, since all
    | increases are attributable to noise. Use @benchmark to get
    | mean, median and maximum instead.
 
      | otde wrote:
      | Thank you! Edited to fix.
 
    | fishmaster wrote:
    | That is very cool.
 
    | eigenspace wrote:
    | Beautiful
 
    | StefanKarpinski wrote:
    | I love the Julia community
 
  | paul_milovanov wrote:
  | looks like they're just multiplying two 100x100 matrices, once?
  | (maybe I'm reading it wrong?) in Julia, runtime would be
  | dominated by compilation + startup time.
  | 
  | A fair comparison with C++ would be to _at least_ include the
  | compilation /linking time into the time reported.
  | 
  | Ditto for Java or any JVM language (you'd have JVM startup cost
  | but that doesn't count the compilation time for bytecode).
  | 
  | Generally, for stuff (scientific computing benchmarks) like
  | this you want to run a lot of computation precisely to avoid
  | stuff like this (i.e you want to fairly allow the cost of
  | compilation & startup amortize)
 
    | machineko wrote:
    | If u just look on the main page u would see they are
    | excluding jitting time (using warm start to measure jitted
    | languages) Dunno why this people cant just read few lines of
    | comments in github page before posting :D
 
| noisy_boy wrote:
| How easy it is to produce a compiled executable in 1.6? I took a
| cursory look at the docs but couldn't spot the steps for doing
| so.
 
  | triztian wrote:
  | I've also looked for this, does it mean that I have to install
  | julia on the target machine and it'll recompile when running?
  | 
  | Or are there steps to produce a binary (much like Go or C or
  | Rust)??
 
    | cbkeller wrote:
    | Currently you can make a relocatable "bundle" / "app" with
    | PackageCompiler.jl, but the bundle itself includes a Julia
    | runtime.
    | 
    | Making a nice small static binary is technically possible
    | using an approach similar to what GPUCompiler.jl does, but
    | the CPU equivalent of that isn't quite ready for primetime.
 
      | ku-man wrote:
      | You forgot to mention that a 'Hello World' standalone file
      | is about 0.5 GB!
 
      | triztian wrote:
      | Thank you for your reply! PackageCompiler looks like the
      | right way.
      | 
      | Do you happen have any links to the static binary
      | procedure? Or links to the current state of efforts for
      | this?
 
        | eigenspace wrote:
        | https://github.com/tshort/StaticCompiler.jl/pull/46
 
    | Sukera wrote:
    | You probably want to check out PackageCompiler.jl
    | (https://julialang.github.io/PackageCompiler.jl/dev/)
 
  | ced wrote:
  | We did it for production code installed at client sites, and it
  | has been very easy for us. YMMV
 
  | dklend122 wrote:
  | That's coming. Pieces are there but still need polish and
  | integration. Fib was around 44kb with no runtime required.
  | 
  | Check out staticcompiler.jl
 
    | superdimwit wrote:
    | In your experience, what are the current limitations?
 
      | eigenspace wrote:
      | There's all sorts of limitations right now. E.g. you can't
      | allocate an array right now, dynamic dispatch is
      | prohibited, there are some bugs too.
      | 
      | Most of this is just a relic from StaticCompiler.jl being a
      | very straightforward slight repurposing of GPUCompiler.jl.
      | It will take some work to make it robust on CPU code, but
      | the path to doing so it pretty strightforward. It just
      | requires dedicated work, but it's not a top priority for
      | anyone who has the know-how currently.
 
        | triztian wrote:
        | I'd love to be able to contribute to this, somewhat new
        | to Julia, but I'm sure I could help with something ...
        | 
        | Do you have any links to what has been currently done?
        | 
        | EDIT: Found this thread so far:
        | https://discourse.julialang.org/t/statically-compiled-
        | and-st...
 
        | eigenspace wrote:
        | This is the PR to look at if you want to try and help:
        | https://github.com/tshort/StaticCompiler.jl/pull/46
        | 
        | I think this isn't really a great place for beginners
        | though unfortunately. This project is tightly coupled to
        | undocumented internals of not only julia's compiler, but
        | also LLVM.jl and GPUCompiler.jl. It'll require a lot of
        | learning to be able to meaningfully contribute at this
        | stage.
 
| ng55QPSK wrote:
| maybe i misread this, but milestone "1.6 blockers" still has 3
| open with "1.6 now considered feature-complete. This milestone
| tracks release-blocking issues." - so how can 1.6 be ready?
 
  | kristofferc wrote:
  | It is simple. Those issues shouldn't have had the milestone.
 
    | ng55QPSK wrote:
    | I see. But you should work on your release process if thing
    | like this happen.
 
      | kristofferc wrote:
      | Sorry for the inconvenience and thanks for the advice.
      | We'll do our best to ensure this doesn't happen again.
 
        | icandoit wrote:
        | You guys are doing great. Julia is really taking shape.
        | Can't wait to jump ship from Python.
        | 
        | It's also nice to see that you (personally) are
        | sponsoring zig development. There is so much more room
        | for improvement in the arena of programming languages.
        | Infrastructure like this is a huge multiplier.
 
        | kristofferc wrote:
        | I'm excited about Zig and I've spent many evenings
        | looking at Andrew's streams. I haven't gotten the time to
        | try it out properly myself but I'm looking forward to it.
 
| ghosty-discord wrote:
| do people use Julia for machine learning model or else? is it
| ready to go
 
___________________________________________________________________
(page generated 2021-03-25 23:00 UTC)