Will Julia ever fix its "using ..." latency problems?

This is actually a quite ellegant solution for long and complex interactive prototyping sessions

May I ask how long you’ve been around with julia? I certainly remember the days of 0.6, where e.g. using Plots took tens of minutes on the very machine I’m typing on now.

Also, there have been multiple links in this thread (and in the linked issues and other things) pointing towards improving that state even more. As a short recap what has happened in the past few months:

  • Deep investigations what made compilation slower than necessary
  • How to remove those unnecessary slow spots
  • Build better package serving infrastructure (PkgServer serving tarballs instead of downloading git repositories from GitHub…)
  • Figure out why some packages and code patterns took a long time to compile and fix those code paths in the compiler
  • Make the compiler itself faster
  • Investigate issues why certain packages increase load time dramatically
  • Fix those packages (this is the recent “crusade on invalidations”, where package code and functions have to be recompiled because a newly loaded packages caused a lot of already cached and compiled functions to have to be recompiled)

Some future work includes:

  • Cache not only lowered & typed code, but also native, compiled machine code
  • Cache more code between environments
  • Cache more code
  • Reduce compiler latency
  • maybe even serve compiled code?
  • Did I mention cache more code, even compiled code?

I’m only 95% sure that nothing similar would crop up, but yes, these specific problems are gone insofar you can’t express that idea at all anymore.

Without eval and @eval, there is no REPL and there is no interactive mode. There’s also no recompilation at runtime and there’s no shadowing of existing things in the same namespace since there’s no way to “redefine” anything like a struct or a function at runtime. There’s also no convenient creating of similar function expressions and writing boilerplate (where you define functions with different names but that can take the same arguments) would be a dread. Julia would just be another statically compiled language like C, C++ or Rust (or any number of other compiled languages).

It certainly wouldn’t be the end of the world and most of the time when people want to use eval, they really shouldn’t anyway (don’t parse & eval strings to emulate bad macros!). Their existence does make certain things much easier and provides a lot of flexibility though, so I’m really glad we have them. You also learn a lot about why it’s a bad idea to allow redefining everything at any time, so being limited to certain places makes the language much more powerful & performant as a whole.

Always remember, the really fast parts in Python are not written in Python :slight_smile:

9 Likes

The search and replace trick to update structs works just fine with modules. I usually go for weeks (working everyday) without restarting my sessions, and I’m not even using Revise (I usually reload manually using @eval MyModule include("myfile")).

Only since about a month. In my bachelor thesis of physics, I wrote rust and python and for my master thesis of physics, I’m hoping to replace both of them with Julia (at least for scientific computing).

I’m happy to see that Julia is very actively developed.

Thank you for your explanation.

Of course.

1 Like

See https://github.com/JuliaLang/julia/pull/38572

2 Likes

I figured that’s why JS is so common, I’d think Go or Elixer would be good for front end, maybe Chrystal one day.

On using DifferentialEquations being slow; I recommend just not pulling in all the DifferentialEquations.jl packages in this way. I regularly use ODE/SDE/jump solvers, but never load the full meta package. I really think that at this point the meta package should only be used for simplifying tutorials aimed at beginners. For solving ODEs usually just

using DiffEqBase, OrdinaryDiffEq

is sufficient to load everything one needs. For SDEs you’ll also load StochasticDiffEq, etc. If you just load the set of component packages you need you’ll find a much reduced import time.

6 Likes

You can find all open performance issues on Github. Listing these on the julialang website would be redundant and overwhelming — that’s not the place for them.

While it is work in progress like all modern programming languages, a lot of people are using Julia productively. Instead of complaining about it being “nearly unusable”, I would recommend that you just invest into learning the workflow that fits the language.

17 Likes

Does jupytext work within IJulia or is it a different deal entirely?

Note:

$ julia --help-hidden
julia [switches] -- [programfile] [args...]
 --compile={yes|no|all|min}Enable or disable JIT compiler, or request exhaustive compilation

I call julia -O0 -compile=min the “Python”-option. It’s some minimal compilation (and yes, Python has compilation too; its is minimal, to bytecode). Feel free to try, -compile=no while that’s going to far, you immediately get all kinds of strangeness.

So officially documented is “no” compilation, as an option, implying interpretation.

I can see your point, while you put them to a very high standard, higher than I guess any proprietary software and most open source.

Before we put in a disadvantages section, it’s good to know what’s already there to fix startup-slowness, or at least link to the (partial, for now) solution.

5 Likes

NOTE: Im not an expert :slight_smile:
But It works with jupyter in general, among other stuff, It allows you to have a textual working representation of a notebook, I have use it for julia and python to produce .py and .jl runnable scripts. It just add a bunch of comments lines to store important info such that where a cell starts and ends or whether it is a markdown/code cell. After that you can use the .jl/.py/etc file alone to start a new session or in synchronization with a .pynb file. You can even drop the .pynb completely and work just using the common text files, but you lose the cell output of previous sessions.

Here and example

# -*- coding: utf-8 -*-
# ---
# jupyter:
#   jupytext:
#     cell_metadata_filter: -all
#     formats: jl,ipynb
#     text_representation:
#       extension: .jl
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.3.2
#   kernelspec:
#     display_name: Julia 1.1.0
#     language: julia
#     name: julia-1.1
# ---

# +
println("How you doooing?")
# -

This is a .jl file equivalent to a .pynb with a single cell with the print statement.

I primarily use it because the .pynb is too noise for version control.

I put every software at a very high standard. I can rant about every software except for maybe Rust.

Julia is one of the better languages.

I accept these outcomes.

I am not sure this discussion is relevant anymore, when I said “undefined behavior” I meant in both the general sense and in the C sense, because for me they are the same. I have read a manual of C99 (made for people that wanted to understand the nuances of the language enough to write a compiler for it) and I have never understood undefined behavior the same way you do. All these spurious examples of undefined behavior fall under the umbrella of undefined behavior in the general sense, and while many times they are mentioned in the context of C they never happened in any compiler that I know of. They are ridiculous just to be easier to imprint the dangers of undefined behavior on young programmers’ minds. The undefined behaviour C will display by breaking rules similar to this one will be similar to the undefined behavior displayed by Julia. The definition of C keeps the possibilities open to anything just to protect compiler maintainers free from user complaints.

1 Like

Ok, then in this case tell me of what use it is the possibility to redefine a const in an interactive session, if from the moment we try to do so our program instantly loses any meaning whatsoever.

What I’m desperately trying to say is that there are two alternatives:

  1. Redefining a const is UB.
  2. Redefining a const c means that occurrences of c can have any possible value that it has ever had during the entire session. This is not UB; it i closer to undefined value, unpecified value, unspecified behavior, whatever you want to call it.

If 1. is true, then we accept that const c = 0; c = 1 can format the hard disk.

The documentation, in its current state, seems to lean more towards 2.

I agree that all this discussion has become quite useless.

None of these outcomes are ruled out by the API as defined at the moment. Please read this again:

this can produce unpredictable behavior or corrupt the state of your program

Once the image is corrupted, anything goes.

1 Like

The problem lies there. What is “unpredictable” behavior? Having any arbitrary value previously assigned is “unpredictable behavior” too, but is not undefined behavior. That’s why I’m saying that from the docs is not clear at all whether reassigning is undefined behavior or more like unspecified value. They are dramatically different concepts.


This might very well be the case, and it is quite unfortunate to be honest. In this case, doing

const c = 0
const c = 1

at the REPL is instant nonsense, you might just as well restart the session (and wait 40 second for using Plots, DifferentialEquations…).

One possible outcome of undefined behavior include the code working as you would expect if the variable was not const. This is clearly intended for REPL use (the documentation says so). The basic idea is: instead of closing and opening the REPL again to redefine a const variable, I can try my luck and just redefine it to make a fast test I wanted to do; if it behaves as I expected this change to behave, then I had luck in my favor and this saved me a few seconds, if something else happens then I did not have luck on my side and will have to restart to adequately test what I wanted. Simple as that. It is a luck/chance/probability/bayesian thing. You have the possibility of play dice with the compiler and get some not-entirely-trustworthy information.

I am not sure if the possible changes in behavior are restricted to just to that one. I understand your point now, if this is the only possible behavior (i.e., the code may or may not act as any of the previous values was yet assigned to the variable) then you could infer more things and not worry about having your disk formatted, XD. It would be better to inquire someone from the Julia internals development about this. In particular, I am not sure if changing the const variable to an object of another type will always error, or it may accept it and end up with a segmentation fault when the variable is referenced, as the object address may not be inlined but the type information can be, for example.

3 Likes

I get what you mean, and I agree that it might be “sufficient” in some circumstances, but please consider that this might affect some tests that silently pass instead of failing. I don’t particularly like this chance-based programming, and I would not like to set foot on an airplane whose fly-by-wire system has been tested this way.


No no, definitely that one is not the only possiblility: it was just an example of an alternative to full UB.


This would be particularly nasty. If reassigning to a const is UB (especially if the type is different), I don’t see any reason not to make it a hard error instead, since anything that follows it would be completely meaningless (actually, in C, UB is “retroactive” too, so also what precedes the invalid operation becomes meaningless: see this example).


In any case, I’ve opened this issue, where I’m not expecting plenty of spam regarding what UB is or isn’t (as witnessed in this thread), but rather a clarifying answer from the core developers.

@Volker_Weissmann DifferentialEquations is a bit unfair, but also getting a lot faster.*

Several plotting packages have sub-sec. startup (but I’m otherwise checking same packages you did/the abstraction plotting packages; what are comparable package/s in Python, i.e. with backends?):

julia> @time using PGFPlotsX
  0.413068 seconds (464.33 k allocations: 29.720 MiB, 10.62% compilation time)

same plotting package you get with Plots.jl, without the abstraction:

julia> @time using GR
  0.815509 seconds (819.21 k allocations: 47.663 MiB, 1.71% gc time, 86.12% compilation time)

There’s been good progress made from 12.7 sec (on your machine), now 70% faster (on my loaded machine, compared to yours):

in 1.9-DEV:

julia> @time using Plots
  3.871938 seconds (5.66 M allocations: 393.934 MiB, 4.29% gc time, 22.05% compilation time: 0% of which was recompilation)

after:
[ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]
 80.083775 seconds (5.59 M allocations: 389.394 MiB, 0.21% gc time, 1.14% compilation time: 0% of which was recompilation)

vs in 1.7.0:

julia> @time using Plots
  6.400478 seconds (9.10 M allocations: 642.353 MiB, 5.92% gc time, 20.97% compilation time)

[ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]
151.895940 seconds (9.11 M allocations: 643.639 MiB, 0.48% gc time, 1.11% compilation time)

I’m testing Plots.jl since you complained, and to your numbers, but the better package by now seems to be Makie.jl, and there are other simpler with very fast startup.

You can actually get instantaneous startup, I understand, of (these/these?) [plotting] packages, by putting in your sysimage, still showing for 1.7.0 without that:

julia> @time using CairoMakie
  8.230858 seconds (12.80 M allocations: 891.117 MiB, 6.84% gc time, 11.23% compilation time)

julia> @time using AlgebraOfGraphics
  8.557753 seconds (13.31 M allocations: 922.143 MiB, 6.76% gc time, 12.52% compilation time)

[the times do not add up for both of above, you only get extra 0.3 sec for the latter after usinging the former, and I believe you can use them together.]

or if you need 3D/OpenGL other backends:

julia> @time using GLMakie
 10.075012 seconds (14.93 M allocations: 1021.257 MiB, 8.08% gc time, 9.91% compilation time)

julia> @time using RPRMakie
  8.130355 seconds (12.83 M allocations: 892.046 MiB, 6.78% gc time, 10.59% compilation time)

* DifferentialEquations.jl also has 70% faster startup (on 1.7.0) at 10 sec. Maybe not great, but likely the slowest package in the Julia ecosystem to start (but fastest at runtime compares to any other language). Since you compare to Python, and it or no language compares for this, not too helpful to look at the slow (by now tolerable?) startup time. Also use can use it from Python, but since you’re then calling Julia, I assume the startup is the same.

With 1.9 not out, it’s of course not yet supported on 1.9, and it might be also much faster after that upgrade, as Plots.jl did, when this fixed:

julia> @time using DifferentialEquations
[ Info: Precompiling DifferentialEquations [0c46a032-eb83-5123-abaf-570d42b7fbaa]
ERROR: LoadError: Sundials is not properly installed. Please run Pkg.build("Sundials")

[I get actually slightly slower timing for Atom, but it could be my machine, and since Atom is in maintenance mode, VS Code is what’s important now (and is fast for me).]

I realized there’s one minor regression on master where I do not get this (convenient) prompt, unlike on 1.7.0 [EDIT: Issue filed, see next comment]

Just filed an issue Missing package install prompt doesn't work when load is behind a macro · Issue #45082 · JuliaLang/julia · GitHub

1 Like