Edit just to mention that Numba solves by and large the middle ground for the domain I work in, despite what Julia proponents have to say.
Edit just to mention that Numba solves by and large the middle ground for the domain I work in, despite what Julia proponents have to say.
That's always the problem with a new programming language. The target for the language is the people that already have something that works. Then a decade passes and that language is no longer a shiny new object, so enthusiasm for it dies, it's just another old language with warts.
Numerical computing is something where there's always been something that works. Before Python it was C and Fortran.
The problem people ran into is that when everything is wrapped around low-level libraries for speed, you eventually run into the catch 22 of using the slower language that you prefer for clarity, or the faster one that makes it acceptable performance-wise.
In other words, with Python, to get the performance you would have got in C or Fortran, you have to code in C or Fortran. Then you're not using Python anymore. The idea (in theory, and a lot in practice) with Julia (or Nim, or other LLVM-targeting languages) is that you don't have this penalty.
So in that sense Julia is providing something that isn't working in Python or Matlab.
I think Julia's not quite what it's cracked up to be, but mostly it is, and I'd probably prefer working with it over Python or Matlab for numerical stuff.
But Python didn't take off because of scientific computing. Google was a heavy user of Python from the start. Python seriously sucked for scientific computing in 2005. I was looking for a new language (the old one wasn't cutting it) and I'd been looking for a use for Python for years. It had some projects but it just was not in a useful state so I went with R, which was quite mature by that time, and it focused on statistical analysis. Years later Python became popular for scientific computing, likely due to the userbase it had built up in other areas.
These days, Nim is a better Cython but with less dynamic temptations and more powerful metaprogramming (and, yes, a much smaller ecosystem..maybe not that much smaller than Python in the late 90s, though). { Not that this is all Nim is...It's actually a really good everything-language that's tricky to summarize in just a few words. }
I remember dynamic languages people picking up on three things in particular: Python apparently being designed to be inherently inefficient, not having proper garbage collection, and having weird scoping. At least Python was something to point people at who rejected Lisp as an alternative to Tcl and Perl for scientific computing.
And before that, analog circuits. Hodgkin and Huxley computed their first results for neuronal activity without a computer.
1. It's very easy to inspect generated code of your kernels where you really need SIMD. For instance:
julia> function my_kernel(xs)
total = zero(eltype(xs))
for x in xs
@fastmath total += x
end
total
end
julia> @code_native debuginfo=:none my_kernel(rand(10))
...
L96:
vaddpd 8(%rcx,%rax,8), %ymm0, %ymm0
vaddpd 40(%rcx,%rax,8), %ymm1, %ymm1
vaddpd 72(%rcx,%rax,8), %ymm2, %ymm2
vaddpd 104(%rcx,%rax,8), %ymm3, %ymm3
addq $16, %rax
cmpq %rax, %rdi
jne L96
...
2. There's a Julia package that does the code gen for vectorization exactly because LLVM does not always get it right: https://chriselrod.github.io/LoopVectorization.jl/stable/exa...3. You can make LLVM explain why it did not vectorize certain loops just like in clang.
Just to be clear: I want to use Julia but without guessing about SIMD use in kernels. Until this is available for complex control flow in Julia, it’s not a game changer in my opinion.
Edit: that kernel is trivial. I have nested control flow to vectorize.
julia> function simple!(ys, xs)
@avx for i = eachindex(xs)
ys[i] = if xs[i] < 3.
xs[i]^2
else
sqrt(xs[i])
end
end
end
This generates vbroadcastsd, vpcmpgtq, vmulpd, vsqrtpd, vblendvpd and vmaskmovpd AVX2 instructions (I don't have AVX512). But more complex control flow does indeed not work; the `@avx` macro errors it can't handle it at the moment. varying float aff[nc], xh[nn], wij[nn], x[nc];
varying int ih[nn];
uniform int t_ = t & (nl - 1);
uniform float k;
for (int j=0; j<nc; j++)
aff[j] = 0.0f;
for (int j=0; j<nn; j++)
for (int i=0; i<nc; i++)
aff[i] += wij[j] * shuffle(xh[j], ih[j]);
for (int i=0; i<nc; i++)
x[i] = 0.1f*(x[i] + x[i]*x[i]*x[i]/3.0f + k*aff[i]);
for (uniform int i=0; i<nn; i++)
xh[i] = insert(rotate(xh[i], 1), 0, extract(x[i/nl], i&(nl-1)));
Just being able to absorb SIMD lanes into the notion of varying vs uniform makes this easy to write, not to mention SIMD operations like shuffle or rotate. In Julia or Numba or CUDA I have to index into arrays, ensure compatible data layout etc. I imagine this could be done with more macrology in Julia, but again why not use something which already works.Sure, but there's always somebody crazy enough to try to implement it :p
From the fact that ISPC can generate C++ (with --emit-c++) I would think their compiler is conceptually very high-level. Since so few new concept are introduced, I wouldn't be surprised if someone would implement the same DSL in Julia at some point, just to see if one can get similar performance.
It's a Clang-based frontend for LLVM, so yeah, no reason Julia couldn't make use of their work. I think the main thing to tap into is the uniform vs varying support, since this drives the whole thing.
For performance you virtually always need to write 'vectorized' code, which is often difficult and memory heavy.
The daily churn of handling input parsing, along with contorting code into vectorized form takes up an extraordinary amount of time when writing Matlab code.
Matlab is certainly not 'good enough' for me! It's just what I'm stuck with at work.
But that's just extremely restrictive. The jit does not work on arbitrary user code.
I have recently been working with a REST API, something I don't do with either Python or Julia normally. I spent probably 10x as long time getting this to work in Python. It was not just a matter of not doing what I wanted, but also in not supporting well established conventions well as well as simply having far more complex APIs than the Julia equivalent.
This is something I frequently find. Julia APIs for doing the same thing as in Python will generally be much easier to work with.
Python APIs also tend to be very OOP oriented and stateful. Meaning there is a lot of mutating of hidden state. Julia APIs tend to show much more clearly what the data flow, is because they follow a more functional approach, where mutation of state is generally avoided. Although Julia is pragmatic. It isn't like working in Haskell.
NOTE: I am not saying Python is a bad language. It would usually be my second choice. I am just trying to say that there are REAL advantages to using Julia, which go far beyond mere performance. I never started using Julia due to performance but due to its expressiveness and clean APIs.