|
| 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) |